1
1
use std:: {
2
2
cmp:: Ordering ,
3
3
io:: { Error , ErrorKind , Result } ,
4
- sync:: Arc ,
5
4
} ;
6
5
7
6
use avalanche_types:: {
8
7
choices:: status:: Status ,
9
8
ids:: { must_deserialize_id, Id } ,
9
+ rpcchainvm,
10
10
} ;
11
11
use avalanche_utils:: rfc3339;
12
12
use chrono:: { DateTime , NaiveDateTime , Utc } ;
13
13
use hmac_sha256:: Hash ;
14
14
use serde:: { Deserialize , Serialize } ;
15
- use tokio:: sync:: RwLock ;
16
15
17
- use crate :: kvvm:: ChainVmInterior ;
16
+ use crate :: kvvm:: ChainVm ;
18
17
19
18
pub const DATA_LEN : usize = 32 ;
20
19
20
+ impl Block {
21
+ pub fn new (
22
+ parent : Id ,
23
+ height : u64 ,
24
+ data : Vec < u8 > ,
25
+ timestamp : DateTime < Utc > ,
26
+ status : Status ,
27
+ ) -> Self {
28
+ Self {
29
+ parent,
30
+ height,
31
+ timestamp,
32
+ data,
33
+ status,
34
+ id : Id :: empty ( ) ,
35
+ bytes : Vec :: default ( ) ,
36
+ vm : None ,
37
+ }
38
+ }
39
+ }
40
+
41
+ pub trait MiniKvvmBlock : rpcchainvm:: concensus:: snowman:: Block + Serialize {
42
+ fn data ( & self ) -> & [ u8 ] ;
43
+ fn initialize ( & mut self , vm : ChainVm ) -> Result < Id > ;
44
+ fn set_status ( & mut self , status : Status ) ;
45
+ }
46
+
21
47
// TODO remove
22
48
// Default is only used as a placeholder for unimplemented block logic
23
49
impl Default for Block {
24
50
fn default ( ) -> Self {
25
51
Self {
26
- id : Some ( Id :: empty ( ) ) ,
52
+ id : Id :: empty ( ) ,
27
53
parent : Id :: empty ( ) ,
28
54
timestamp : DateTime :: < Utc > :: from_utc ( NaiveDateTime :: from_timestamp ( 0 , 0 ) , Utc ) ,
29
55
bytes : Vec :: default ( ) ,
30
56
height : 0 ,
31
57
status : Status :: Unknown ( "" . to_string ( ) ) ,
32
58
data : Vec :: default ( ) ,
59
+ vm : None ,
33
60
}
34
61
}
35
62
}
36
63
37
64
/// snow/consensus/snowman/Block
38
65
/// ref. https://pkg.go.dev/github.com/ava-labs/avalanchego/snow/consensus/snowman#Block
39
- #[ derive( Serialize , Debug , Clone , Deserialize ) ]
66
+ #[ derive( Serialize , Clone , Deserialize ) ]
40
67
pub struct Block {
41
68
#[ serde( deserialize_with = "must_deserialize_id" ) ]
42
69
pub parent : Id ,
@@ -48,65 +75,120 @@ pub struct Block {
48
75
49
76
// generated not serialized
50
77
#[ serde( skip) ]
51
- id : Option < Id > ,
78
+ id : Id ,
52
79
// generated not serialized
53
80
#[ serde( skip) ]
54
81
bytes : Vec < u8 > ,
82
+ #[ serde( skip) ]
83
+ vm : Option < ChainVm > ,
55
84
}
56
85
57
- impl Block {
58
- pub fn new (
59
- parent : Id ,
60
- height : u64 ,
61
- data : Vec < u8 > ,
62
- timestamp : DateTime < Utc > ,
63
- status : Status ,
64
- ) -> Result < Self > {
65
- Ok ( Self {
66
- parent,
67
- height,
68
- timestamp,
69
- data,
70
- status,
71
- id : None ,
72
- bytes : Vec :: default ( ) ,
73
- } )
86
+ #[ tonic:: async_trait]
87
+ impl rpcchainvm:: concensus:: snowman:: Decidable for Block {
88
+ /// id returns the ID of this block
89
+ async fn id ( & self ) -> Id {
90
+ self . id
74
91
}
75
92
76
- pub fn parent ( & self ) -> Id {
77
- self . parent
93
+ /// status returns the status of this block
94
+ async fn status ( & self ) -> Status {
95
+ self . status . clone ( )
78
96
}
79
97
80
- /// id returns the ID of this block
81
- pub fn id ( & self ) -> Option < Id > {
82
- self . id
98
+ /// Accepts this element.
99
+ async fn accept ( & mut self ) -> Result < ( ) > {
100
+ let vm = self . vm . clone ( ) ;
101
+ let vm = vm. ok_or ( Error :: new ( ErrorKind :: Other , "no vm associated with block" ) ) ?;
102
+ let mut inner = vm. inner . write ( ) . await ;
103
+
104
+ self . status = Status :: Accepted ;
105
+
106
+ // add newly accepted block to state
107
+ inner
108
+ . state
109
+ . put_block ( self . clone ( ) , vm. clone ( ) )
110
+ . await
111
+ . map_err ( |e| Error :: new ( ErrorKind :: Other , format ! ( "failed to put block: {:?}" , e) ) ) ?;
112
+
113
+ // set last accepted block to this block id
114
+ inner
115
+ . state
116
+ . set_last_accepted_block_id ( & self . id )
117
+ . await
118
+ . map_err ( |e| Error :: new ( ErrorKind :: Other , format ! ( "failed to put block: {:?}" , e) ) ) ?;
119
+
120
+ // remove from verified blocks
121
+ inner. verified_blocks . remove ( & self . id ) ;
122
+ Ok ( ( ) )
123
+ }
124
+
125
+ /// Rejects this element.
126
+ async fn reject ( & mut self ) -> Result < ( ) > {
127
+ let vm = self . vm . clone ( ) ;
128
+ let vm = vm. ok_or ( Error :: new ( ErrorKind :: Other , "no vm associated with block" ) ) ?;
129
+ let mut inner = vm. inner . write ( ) . await ;
130
+
131
+ self . status = Status :: Rejected ;
132
+
133
+ // add newly rejected block to state
134
+ inner
135
+ . state
136
+ . put_block ( self . clone ( ) , vm. clone ( ) )
137
+ . await
138
+ . map_err ( |e| Error :: new ( ErrorKind :: Other , format ! ( "failed to put block: {:?}" , e) ) ) ?;
139
+
140
+ // remove from verified, as it is rejected
141
+ inner. verified_blocks . remove ( & self . id ) ;
142
+ Ok ( ( ) )
83
143
}
144
+ }
84
145
85
- pub fn timestamp ( & self ) -> & DateTime < Utc > {
86
- & self . timestamp
146
+ #[ tonic:: async_trait]
147
+ impl rpcchainvm:: concensus:: snowman:: Block for Block {
148
+ /// bytes returns the binary representation of this block
149
+ async fn bytes ( & self ) -> & [ u8 ] {
150
+ & self . bytes
151
+ }
152
+
153
+ /// height returns this block's height. The genesis block has height 0.
154
+ async fn height ( & self ) -> u64 {
155
+ self . height
156
+ }
157
+
158
+ async fn timestamp ( & self ) -> u64 {
159
+ self . timestamp . timestamp ( ) as u64
160
+ }
161
+
162
+ async fn parent ( & self ) -> Id {
163
+ self . parent
87
164
}
88
165
89
166
/// verify ensures that the state of the block is expected.
90
- pub async fn verify ( & self , inner : & Arc < RwLock < ChainVmInterior > > ) -> Result < ( ) > {
91
- let vm = inner. read ( ) . await ;
167
+ async fn verify ( & self ) -> Result < ( ) > {
168
+ let vm = self
169
+ . vm
170
+ . clone ( )
171
+ . ok_or ( Error :: new ( ErrorKind :: Other , "no reference to vm" ) ) ?;
172
+
173
+ let vm = vm. inner . read ( ) . await ;
92
174
93
175
match vm. state . get_block ( self . parent ) . await ? {
94
176
Some ( parent_block) => {
95
177
// Ensure block height comes right after its parent's height
96
- if parent_block. height ( ) + 1 != self . height ( ) {
178
+ if parent_block. height ( ) . await + 1 != self . height {
97
179
return Err ( Error :: new (
98
180
ErrorKind :: InvalidData ,
99
181
"failed to verify block invalid height" ,
100
182
) ) ;
101
183
}
102
184
// Ensure block timestamp is after its parent's timestamp.
103
- if self . timestamp ( ) . cmp ( parent_block. timestamp ( ) ) == Ordering :: Less {
185
+ if self . timestamp ( ) . await . cmp ( & parent_block. timestamp ( ) . await ) == Ordering :: Less {
104
186
return Err ( Error :: new (
105
187
ErrorKind :: InvalidData ,
106
188
format ! (
107
189
"block timestamp: {} is after parents: {}" ,
108
- self . timestamp( ) ,
109
- parent_block. timestamp( )
190
+ self . timestamp( ) . await ,
191
+ parent_block. timestamp( ) . await
110
192
) ,
111
193
) ) ;
112
194
}
@@ -118,46 +200,38 @@ impl Block {
118
200
) ) ,
119
201
}
120
202
}
203
+ }
121
204
205
+ impl MiniKvvmBlock for Block {
122
206
/// data returns the block payload.
123
- pub fn data ( & self ) -> & [ u8 ] {
207
+ fn data ( & self ) -> & [ u8 ] {
124
208
& self . data
125
209
}
126
210
127
- /// bytes returns the binary representation of this block
128
- pub fn bytes ( & self ) -> & [ u8 ] {
129
- & self . bytes
130
- }
131
-
132
- /// height returns this block's height. The genesis block has height 0.
133
- pub fn height ( & self ) -> u64 {
134
- self . height
135
- }
136
-
137
- /// status returns the status of this block
138
- pub fn status ( & self ) -> Status {
139
- self . status . clone ( )
211
+ fn set_status ( & mut self , status : Status ) {
212
+ self . status = status;
140
213
}
141
214
142
215
/// initialize populates the generated fields (id, bytes) of the the block and
143
216
/// returns the generated id.
144
- pub fn initialize ( & mut self ) -> Result < Id > {
145
- if self . id . is_none ( ) {
217
+ fn initialize ( & mut self , vm : ChainVm ) -> Result < Id > {
218
+ if self . id . is_empty ( ) {
146
219
match serde_json:: to_vec ( & self ) {
147
220
// Populate generated fields
148
221
Ok ( block_bytes) => {
149
222
let block_data = block_bytes. as_slice ( ) ;
150
223
let block_id = to_block_id ( & block_data) ;
151
- self . id = Some ( block_id) ;
224
+ self . id = block_id;
152
225
self . bytes = block_bytes;
153
- return Ok ( self . id . unwrap ( ) ) ;
226
+ self . vm = Some ( vm) ;
227
+ return Ok ( self . id ) ;
154
228
}
155
229
Err ( error) => {
156
230
return Err ( Error :: new ( ErrorKind :: NotFound , error) ) ;
157
231
}
158
232
}
159
233
}
160
- Ok ( self . id . unwrap ( ) )
234
+ Ok ( self . id )
161
235
}
162
236
}
163
237
@@ -169,10 +243,11 @@ fn new_id(bytes: [u8; DATA_LEN]) -> Id {
169
243
Id :: from_slice ( & bytes)
170
244
}
171
245
172
- #[ test]
173
- fn test_serialization_round_trip ( ) {
246
+ #[ tokio:: test]
247
+ async fn test_serialization_round_trip ( ) {
248
+ use rpcchainvm:: concensus:: snowman:: Block as _; //Bring the block trait into scope for [.parent()]
174
249
let block = Block :: default ( ) ;
175
250
let writer = serde_json:: to_vec ( & block) . unwrap ( ) ;
176
251
let value: Block = serde_json:: from_slice ( & writer) . unwrap ( ) ;
177
- assert_eq ! ( block. parent( ) , value. parent( ) ) ;
252
+ assert_eq ! ( block. parent( ) . await , value. parent( ) . await ) ;
178
253
}
0 commit comments