Skip to content

Commit 35d82df

Browse files
produces vm binary compatible with avalanchego
1 parent 6df3fda commit 35d82df

File tree

14 files changed

+747
-1092
lines changed

14 files changed

+747
-1092
lines changed

mini-kvvm/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ path = "src/bin/mini-kvvm/main.rs"
1616
[dependencies]
1717
async-trait = "0.1.53"
1818
avalanche-proto = { version = "0.15.1" }
19-
avalanche-types = { version = "0.0.10", features = ["proto"] }
19+
avalanche-types = "0.0.27" #NOTE avalanche-types must be updated from branch ava-types-plugin-logic for this to work
2020
avalanche-utils = { version="0.0.3", features = ["rfc3339"] }
2121
bytes = "1.1.0"
2222
chrono = "0.4.19"
2323
clap = { version = "3.1.8", features = ["cargo", "derive"] }
2424
env_logger = "0.9.0"
2525
hmac-sha256 = "1.1"
2626
jsonrpc-core = "18.0"
27-
jsonrpc-http-server = "18.0"
27+
jsonrpc-derive = "18.0"
2828
log = "0.4.16"
2929
num-traits = "0.2.15"
3030
num-derive = "0.3"

mini-kvvm/src/bin/mini-kvvm/main.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use std::io::Result;
1+
use std::{io::Result, sync::Arc};
22

3-
use avalanche_types::rpcchainvm::plugin;
43
use clap::{crate_version, Arg, Command};
54
use log::info;
6-
use mini_kvvm::{engine, genesis, kvvm};
5+
use mini_kvvm::{genesis, kvvm};
6+
use tokio::sync::RwLock;
77

88
pub const APP_NAME: &str = "mini-kvvm-rs";
99

@@ -43,7 +43,14 @@ async fn main() -> Result<()> {
4343
}
4444

4545
info!("starting mini-kvvm-rs");
46-
plugin::serve(engine::VmServer::new(kvvm::ChainVmInterior::new())).await
46+
let mini_kvvm = kvvm::ChainVm::new(Arc::new(RwLock::new(kvvm::ChainVmInterior::default())));
47+
let rpcchain = avalanche_types::rpcchainvm::vm::server::Server::new(mini_kvvm);
48+
49+
avalanche_types::rpcchainvm::plugin::serve(rpcchain)
50+
.await
51+
.expect("failed to start server");
52+
53+
Ok(())
4754
}
4855

4956
pub fn command_genesis() -> Command<'static> {

mini-kvvm/src/block.rs

Lines changed: 133 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,69 @@
11
use std::{
22
cmp::Ordering,
33
io::{Error, ErrorKind, Result},
4-
sync::Arc,
54
};
65

76
use avalanche_types::{
87
choices::status::Status,
98
ids::{must_deserialize_id, Id},
9+
rpcchainvm,
1010
};
1111
use avalanche_utils::rfc3339;
1212
use chrono::{DateTime, NaiveDateTime, Utc};
1313
use hmac_sha256::Hash;
1414
use serde::{Deserialize, Serialize};
15-
use tokio::sync::RwLock;
1615

17-
use crate::kvvm::ChainVmInterior;
16+
use crate::kvvm::ChainVm;
1817

1918
pub const DATA_LEN: usize = 32;
2019

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+
2147
// TODO remove
2248
// Default is only used as a placeholder for unimplemented block logic
2349
impl Default for Block {
2450
fn default() -> Self {
2551
Self {
26-
id: Some(Id::empty()),
52+
id: Id::empty(),
2753
parent: Id::empty(),
2854
timestamp: DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc),
2955
bytes: Vec::default(),
3056
height: 0,
3157
status: Status::Unknown("".to_string()),
3258
data: Vec::default(),
59+
vm: None,
3360
}
3461
}
3562
}
3663

3764
/// snow/consensus/snowman/Block
3865
/// 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)]
4067
pub struct Block {
4168
#[serde(deserialize_with = "must_deserialize_id")]
4269
pub parent: Id,
@@ -48,65 +75,120 @@ pub struct Block {
4875

4976
// generated not serialized
5077
#[serde(skip)]
51-
id: Option<Id>,
78+
id: Id,
5279
// generated not serialized
5380
#[serde(skip)]
5481
bytes: Vec<u8>,
82+
#[serde(skip)]
83+
vm: Option<ChainVm>,
5584
}
5685

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
7491
}
7592

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()
7896
}
7997

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(())
83143
}
144+
}
84145

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
87164
}
88165

89166
/// 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;
92174

93175
match vm.state.get_block(self.parent).await? {
94176
Some(parent_block) => {
95177
// 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 {
97179
return Err(Error::new(
98180
ErrorKind::InvalidData,
99181
"failed to verify block invalid height",
100182
));
101183
}
102184
// 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 {
104186
return Err(Error::new(
105187
ErrorKind::InvalidData,
106188
format!(
107189
"block timestamp: {} is after parents: {}",
108-
self.timestamp(),
109-
parent_block.timestamp()
190+
self.timestamp().await,
191+
parent_block.timestamp().await
110192
),
111193
));
112194
}
@@ -118,46 +200,38 @@ impl Block {
118200
)),
119201
}
120202
}
203+
}
121204

205+
impl MiniKvvmBlock for Block {
122206
/// data returns the block payload.
123-
pub fn data(&self) -> &[u8] {
207+
fn data(&self) -> &[u8] {
124208
&self.data
125209
}
126210

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;
140213
}
141214

142215
/// initialize populates the generated fields (id, bytes) of the the block and
143216
/// 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() {
146219
match serde_json::to_vec(&self) {
147220
// Populate generated fields
148221
Ok(block_bytes) => {
149222
let block_data = block_bytes.as_slice();
150223
let block_id = to_block_id(&block_data);
151-
self.id = Some(block_id);
224+
self.id = block_id;
152225
self.bytes = block_bytes;
153-
return Ok(self.id.unwrap());
226+
self.vm = Some(vm);
227+
return Ok(self.id);
154228
}
155229
Err(error) => {
156230
return Err(Error::new(ErrorKind::NotFound, error));
157231
}
158232
}
159233
}
160-
Ok(self.id.unwrap())
234+
Ok(self.id)
161235
}
162236
}
163237

@@ -169,10 +243,11 @@ fn new_id(bytes: [u8; DATA_LEN]) -> Id {
169243
Id::from_slice(&bytes)
170244
}
171245

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()]
174249
let block = Block::default();
175250
let writer = serde_json::to_vec(&block).unwrap();
176251
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);
178253
}

0 commit comments

Comments
 (0)