Skip to content

Commit 15678d2

Browse files
authored
MVP (#72)
* MVP and tests Signed-off-by: Sam Batschelet <[email protected]>
1 parent 765dd05 commit 15678d2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2325
-2015
lines changed

.github/workflows/test-and-release.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,13 @@ jobs:
110110
uses: arduino/setup-protoc@v1
111111
with:
112112
version: '3.x'
113+
- name: Build plugin
114+
uses: actions-rs/cargo@v1
115+
with:
116+
command: build
117+
args: --release --bin mini-kvvm
113118
- name: Run e2e tests
114-
run: scripts/tests.e2e.sh 1.7.14
119+
run: VM_PLUGIN_PATH=/home/runner/work/mini-kvvm-rs/mini-kvvm-rs/target/release/mini-kvvm scripts/tests.e2e.sh
115120

116121
release:
117122
name: Release ${{ matrix.job.target }} (${{ matrix.job.os }})

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ Cargo.lock
1414

1515
# ignore dev tools
1616
.vscode
17+
18+
# ignore private keys
19+
.*-pk

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
[workspace]
22
members = [
33
"mini-kvvm",
4-
"tests/e2e"
4+
"tests/e2e",
5+
"cli",
56
]
7+
8+
[patch.crates-io]
9+
# TODO: replace
10+
eip-712 = {git="https://github.com/darioush/EIP-712.git"}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ cp \
2121
./target/x86_64-unknown-linux-musl/release/mini-kvvm-rs \
2222
${HOME}/go/src/github.com/ava-labs/avalanchego/build/plugins/qBnAKUQ2mxjMHCneWjq5nFuhntoWrsKsCjaYSouFjpuCB2o5d
2323
```
24+
##

cli/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.*-pk

cli/Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "cli"
3+
version = "0.0.0"
4+
edition = "2021"
5+
rust-version = "1.65"
6+
publish = false
7+
description = "cli for issuing simple rpc commands to mini-kvvm"
8+
license = "BSD-3-Clause"
9+
homepage = "https://avax.network"
10+
11+
[dependencies]
12+
avalanche-types = { version = "0.0.132", features = ["rpcchainvm"] }
13+
clap = { version = "4.0", features = ["derive"] }
14+
hex = "0.4.3"
15+
jsonrpc-core = "18.0.0"
16+
jsonrpc-core-client = { version = "18.0.0" }
17+
jsonrpc-client-transports = "18.0.0"
18+
jsonrpc-derive = "18.0"
19+
log = "0.4.17"
20+
mini-kvvm = {path = "../mini-kvvm"}
21+
serde = { version = "1.0.147", features = ["derive"] }
22+
serde_json = "1.0.87"
23+
tokio = { version = "1.21.2", features = ["full"] }

cli/src/main.rs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
use avalanche_types::key;
2+
use clap::{Parser, Subcommand};
3+
use jsonrpc_client_transports::{transports, RpcError};
4+
use jsonrpc_core::futures;
5+
use mini_kvvm::api::ServiceClient as Client;
6+
use mini_kvvm::api::{DecodeTxArgs, IssueTxArgs, ResolveArgs};
7+
use mini_kvvm::chain::tx::{decoder, tx::TransactionType, unsigned::TransactionData};
8+
use std::error;
9+
use std::fs::File;
10+
use std::io::{Result, Write};
11+
use std::path::Path;
12+
13+
#[derive(Parser)]
14+
#[command(version, about, long_about = None)]
15+
struct Cli {
16+
/// Endpoint for RPC calls.
17+
#[clap(long)]
18+
endpoint: String,
19+
20+
/// Private key file.
21+
#[clap(long, default_value = ".mini-kvvm-cli-pk")]
22+
private_key_file: String,
23+
24+
/// Which subcommand to call.
25+
#[command(subcommand)]
26+
command: Command,
27+
}
28+
29+
#[derive(Subcommand, Debug)]
30+
enum Command {
31+
Bucket {
32+
bucket: String,
33+
},
34+
Set {
35+
bucket: String,
36+
key: String,
37+
value: String,
38+
},
39+
Delete {
40+
bucket: String,
41+
key: String,
42+
},
43+
Get {
44+
bucket: String,
45+
key: String,
46+
},
47+
}
48+
49+
#[tokio::main]
50+
async fn main() -> std::result::Result<(), Box<dyn error::Error>> {
51+
let cli = Cli::parse();
52+
53+
let secret_key = get_or_create_pk(&cli.private_key_file)?;
54+
let connection = transports::http::connect::<Client>(&cli.endpoint);
55+
let client = futures::executor::block_on(connection)?;
56+
ping(&client).await?;
57+
58+
if let Command::Get { bucket, key } = &cli.command {
59+
futures::executor::block_on(client.resolve(ResolveArgs {
60+
bucket: bucket.as_bytes().to_vec(),
61+
key: key.as_bytes().to_vec(),
62+
}))
63+
.map_err(|e| e.to_string())?;
64+
}
65+
66+
let tx = command_to_tx(cli.command)?;
67+
68+
futures::executor::block_on(sign_and_submit(&client, &secret_key, tx))
69+
.map_err(|e| e.to_string().into())
70+
}
71+
72+
fn command_to_tx(command: Command) -> Result<TransactionData> {
73+
match command {
74+
Command::Bucket { bucket } => Ok(bucket_tx(bucket)),
75+
Command::Set { bucket, key, value } => Ok(set_tx(bucket, key, value.as_bytes().to_vec())),
76+
Command::Delete { bucket, key } => Ok(delete_tx(bucket, key)),
77+
_ => Err(std::io::Error::new(
78+
std::io::ErrorKind::Other,
79+
"not a supported tx",
80+
)),
81+
}
82+
}
83+
84+
fn get_or_create_pk(path: &str) -> Result<key::secp256k1::private_key::Key> {
85+
if !Path::new(path).try_exists()? {
86+
let secret_key = key::secp256k1::private_key::Key::generate().unwrap();
87+
let mut f = File::create(path)?;
88+
let hex = hex::encode(&secret_key.to_bytes());
89+
f.write_all(hex.as_bytes())?;
90+
return Ok(secret_key);
91+
}
92+
let contents = std::fs::read_to_string(path)?;
93+
let parsed = hex::decode(contents)
94+
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
95+
key::secp256k1::private_key::Key::from_bytes(&parsed)
96+
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
97+
}
98+
99+
fn bucket_tx(bucket: String) -> TransactionData {
100+
TransactionData {
101+
typ: TransactionType::Bucket,
102+
bucket,
103+
key: "".to_string(),
104+
value: vec![],
105+
}
106+
}
107+
108+
fn set_tx(bucket: String, key: String, value: Vec<u8>) -> TransactionData {
109+
TransactionData {
110+
typ: TransactionType::Set,
111+
bucket,
112+
key,
113+
value,
114+
}
115+
}
116+
117+
fn delete_tx(bucket: String, key: String) -> TransactionData {
118+
TransactionData {
119+
typ: TransactionType::Delete,
120+
bucket,
121+
key,
122+
value: vec![],
123+
}
124+
}
125+
126+
async fn ping(client: &Client) -> Result<()> {
127+
let error_handling =
128+
|e: RpcError| std::io::Error::new(std::io::ErrorKind::Other, e.to_string());
129+
let resp = client.ping().await.map_err(error_handling);
130+
dbg!(resp.is_ok());
131+
dbg!(&resp);
132+
Ok(())
133+
}
134+
135+
async fn sign_and_submit(
136+
client: &Client,
137+
pk: &key::secp256k1::private_key::Key,
138+
tx_data: TransactionData,
139+
) -> Result<()> {
140+
let error_handling =
141+
|e: RpcError| std::io::Error::new(std::io::ErrorKind::Other, dbg!(e).to_string());
142+
let resp = client
143+
.decode_tx(DecodeTxArgs { tx_data })
144+
.await
145+
.map_err(error_handling)?;
146+
147+
let typed_data = &resp.typed_data;
148+
149+
let dh = decoder::hash_structured_data(typed_data)?;
150+
let sig = pk.sign_digest(&dh.as_bytes())?;
151+
152+
let resp = client
153+
.issue_tx(IssueTxArgs {
154+
typed_data: resp.typed_data,
155+
signature: sig.to_bytes().to_vec(),
156+
})
157+
.await
158+
.map_err(error_handling)?;
159+
println!("response: {:?}", resp);
160+
Ok(())
161+
}

mini-kvvm/Cargo.toml

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "mini-kvvm"
33
version = "0.0.0"
44
edition = "2021"
5-
rust-version = "1.63"
5+
rust-version = "1.65"
66
publish = false
77
description = "Mini key-value store VM for Avalanche in Rust"
88
license = "BSD-3-Clause"
@@ -14,39 +14,37 @@ name = "mini-kvvm"
1414
path = "src/bin/mini-kvvm/main.rs"
1515

1616
[dependencies]
17-
avalanche-proto = { version = "0.16.0" }
18-
avalanche-types = { version = "0.0.38" }
17+
avalanche-proto = { version = "0.19.0" }
18+
avalanche-types = { version = "0.0.132", features = ["rpcchainvm"] }
1919
byteorder = "1.4.3"
20-
chan = "0.1.23"
2120
chrono = "0.4.19"
2221
crossbeam-channel = "0.5.6"
2322
derivative = "2.2.0"
2423
dyn-clone = "1.0.9"
2524
ethereum-types = { version = "0.14.0" }
26-
clap = { version = "3.1.17", features = ["cargo", "derive"] }
25+
clap = { version = "4.0.9", features = ["cargo", "derive"] }
26+
eip-712 = "0.1.0"
2727
env_logger = "0.9.0"
2828
hex = "0.4.3"
29+
http = "0.2.8"
2930
jsonrpc-core = "18.0.0"
3031
jsonrpc-core-client = { version = "18.0.0" }
3132
jsonrpc-derive = "18.0"
3233
log = "0.4.17"
3334
lru = "0.8.0"
3435
prost = "0.11.0"
36+
ripemd = "0.1.3"
3537
semver = "1.0.13"
3638
serde = { version = "1.0.144", features = ["derive"] }
3739
serde_json = "1.0.85"
3840
serde_yaml = "0.9.10"
3941
sha3 = "0.10.2"
40-
tokio = { version = "1.20.1", features = ["fs", "rt-multi-thread"] }
41-
tokio-stream = { version = "0.1.9", features = ["net"] }
42-
tonic = { version = "0.8.1", features = ["gzip"] }
42+
tokio = { version = "1.21.2", features = ["fs", "rt-multi-thread"] }
43+
tokio-stream = { version = "0.1.11", features = ["net"] }
44+
tonic = { version = "0.8.2", features = ["gzip"] }
4345
tonic-health = "0.7"
4446
typetag = "0.2"
4547

46-
[[test]]
47-
name = "integration"
48-
path = "tests/integration_tests.rs"
49-
50-
[dev-dependencies]
48+
[dev-dependencies]
5149
jsonrpc-tcp-server = "18.0.0"
52-
futures-test = "0.3.24"
50+
futures-test = "0.3.24"

mini-kvvm/src/api/mod.rs

Lines changed: 6 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ use jsonrpc_core::{BoxFuture, Error, ErrorCode, Result};
55
use jsonrpc_derive::rpc;
66
use serde::{Deserialize, Serialize};
77

8-
use crate::chain::{storage::ValueMeta, tx, tx::decoder::TypedData};
8+
use crate::chain::{
9+
storage::ValueMeta,
10+
tx::decoder::TypedData,
11+
tx::{self},
12+
};
913

1014
#[rpc]
1115
pub trait Service {
1216
#[rpc(name = "ping")]
1317
fn ping(&self) -> BoxFuture<Result<PingResponse>>;
1418

15-
#[rpc(name = "issue_raw_tx")]
16-
fn issue_raw_tx(&self, params: IssueRawTxArgs) -> BoxFuture<Result<IssueRawTxResponse>>;
17-
1819
#[rpc(name = "issue_tx")]
1920
fn issue_tx(&self, params: IssueTxArgs) -> BoxFuture<Result<IssueTxResponse>>;
2021

@@ -23,21 +24,6 @@ pub trait Service {
2324

2425
#[rpc(name = "resolve")]
2526
fn resolve(&self, params: ResolveArgs) -> BoxFuture<Result<ResolveResponse>>;
26-
27-
#[rpc(name = "build_block")]
28-
fn build_block(&self, params: BuildBlockArgs) -> BoxFuture<Result<BuildBlockResponse>>;
29-
30-
#[rpc(name = "get_block")]
31-
fn get_block(&self, params: GetBlockArgs) -> BoxFuture<Result<GetBlockResponse>>;
32-
33-
#[rpc(name = "last_accepted")]
34-
fn last_accepted(&self) -> BoxFuture<Result<LastAcceptedResponse>>;
35-
36-
#[rpc(name = "parse_block")]
37-
fn parse_block(&self, params: ParseBlockArgs) -> BoxFuture<Result<ParseBlockResponse>>;
38-
39-
#[rpc(name = "put_block")]
40-
fn put_block(&self, params: PutBlockArgs) -> BoxFuture<Result<PutBlockResponse>>;
4127
}
4228

4329
#[derive(Deserialize, Serialize, Debug)]
@@ -59,6 +45,7 @@ pub struct IssueRawTxResponse {
5945
#[derive(Deserialize, Serialize, Debug)]
6046
pub struct IssueTxArgs {
6147
pub typed_data: TypedData,
48+
pub signature: Vec<u8>,
6249
}
6350

6451
#[derive(Deserialize, Serialize, Debug)]
@@ -90,51 +77,6 @@ pub struct ResolveResponse {
9077
pub meta: ValueMeta,
9178
}
9279

93-
#[derive(Deserialize, Serialize, Debug)]
94-
pub struct BuildBlockArgs {}
95-
96-
#[derive(Deserialize, Serialize, Debug)]
97-
pub struct BuildBlockResponse {
98-
pub block: Vec<u8>,
99-
}
100-
101-
#[derive(Deserialize, Serialize, Debug)]
102-
pub struct GetBlockArgs {
103-
#[serde(deserialize_with = "ids::must_deserialize_id")]
104-
pub id: ids::Id,
105-
}
106-
107-
#[derive(Deserialize, Serialize, Debug)]
108-
pub struct GetBlockResponse {
109-
pub block: Vec<u8>,
110-
}
111-
112-
#[derive(Deserialize, Serialize, Debug)]
113-
pub struct LastAcceptedResponse {
114-
pub id: ids::Id,
115-
}
116-
117-
#[derive(Deserialize, Serialize, Debug)]
118-
pub struct ParseBlockArgs {
119-
pub bytes: Vec<u8>,
120-
}
121-
122-
#[derive(Deserialize, Serialize, Debug)]
123-
pub struct ParseBlockResponse {
124-
pub block: Vec<u8>,
125-
}
126-
127-
#[derive(Deserialize, Serialize, Debug)]
128-
pub struct PutBlockArgs {
129-
pub bytes: Vec<u8>,
130-
}
131-
132-
#[derive(Deserialize, Serialize, Debug)]
133-
pub struct PutBlockResponse {
134-
#[serde(deserialize_with = "ids::must_deserialize_id")]
135-
pub id: ids::Id,
136-
}
137-
13880
pub fn create_jsonrpc_error(e: std::io::Error) -> Error {
13981
let mut error = Error::new(ErrorCode::InternalError);
14082
error.message = format!("{}", e);

0 commit comments

Comments
 (0)