diff --git a/Cargo.lock b/Cargo.lock index f84ebffdcc..744dec80a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,6 +27,30 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "agsol-borsh-schema" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "689a15901649a39efba997c9b75b10496f0d8fc4b57244833dbbf17091a9f55e" +dependencies = [ + "agsol-borsh-schema-derive", + "anyhow", + "heck 0.3.3", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", +] + +[[package]] +name = "agsol-borsh-schema-derive" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60811a9517ead003173bfb969dd3fb86fd4454deacc1d84ea59d26a74452c751" +dependencies = [ + "quote 1.0.21", + "syn 1.0.99", +] + [[package]] name = "ahash" version = "0.7.6" @@ -5937,6 +5961,7 @@ dependencies = [ name = "solana-cli" version = "1.9.29" dependencies = [ + "agsol-borsh-schema", "anyhow", "bincode", "bs58", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 84929f58d4..ea50da70ae 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -10,6 +10,7 @@ homepage = "https://solana.com/" documentation = "https://docs.rs/solana-cli" [dependencies] +agsol-borsh-schema = { version = "0.0.2", features = ["full"] } bincode = "1.3.3" bs58 = "0.4.0" clap = "2.33.1" diff --git a/cli/src/evm.rs b/cli/src/evm.rs index f2d9f95209..d8e0b29011 100644 --- a/cli/src/evm.rs +++ b/cli/src/evm.rs @@ -68,6 +68,28 @@ impl EvmSubCommands for App<'_, '_> { .long("lamports") .help("Amount in lamports"))) + .subcommand( + SubCommand::with_name("generate-borsh-schema") + .about("Generate Borsh schema for EVM instructions") + .display_order(3) + .arg( + Arg::with_name("input_path") + .short("i") + .long("input") + .value_name("DIR") + .takes_value(true) + .required(true) + .help("Parse Rust files from DIR for a borsh schema"), + ) + .arg( + Arg::with_name("schema_path") + .long("schema-dir") + .value_name("DIR") + .takes_value(true) + .default_value("schema") + .help("Use DIR as generated schema location"), + )) + // Hidden commands @@ -152,6 +174,11 @@ pub enum EvmCliCommand { amount: u64, }, + GenerateBorshSchema { + input_path: PathBuf, + schema_path: PathBuf, + }, + // Hidden commands SendRawTx { raw_tx: PathBuf, @@ -192,6 +219,9 @@ impl EvmCliCommand { Self::TransferToEvm { address, amount } => { transfer(rpc_client, config, *address, *amount)?; } + Self::GenerateBorshSchema { input_path, schema_path } => { + generate_borsh_schema(input_path, schema_path)?; + } // Hidden commands Self::SendRawTx { raw_tx } => { send_raw_tx(rpc_client, config, raw_tx)?; @@ -262,8 +292,8 @@ fn transfer( let message = Message::new(&ixs, Some(&from.pubkey())); let mut create_account_tx = Transaction::new_unsigned(message); - let (blockhash, _last_height) = rpc_client - .get_latest_blockhash_with_commitment(CommitmentConfig::default())?; + let (blockhash, _last_height) = + rpc_client.get_latest_blockhash_with_commitment(CommitmentConfig::default())?; create_account_tx.sign(&config.signers, blockhash); @@ -276,6 +306,12 @@ fn transfer( Ok(()) } +fn generate_borsh_schema>(input_path: P, schema_path: P) -> anyhow::Result<()> { + fs::create_dir_all(&schema_path)?; + let layouts = agsol_borsh_schema::generate_layouts(input_path)?; + agsol_borsh_schema::generate_output(&layouts, schema_path) +} + fn find_block_header( rpc_client: &RpcClient, expected_block_hash: evm::H256, @@ -332,8 +368,8 @@ fn send_raw_tx>( let msg = Message::new(&[ix], Some(&signer.pubkey())); let mut tx = Transaction::new_unsigned(msg); - let (blockhash, _last_height) = rpc_client - .get_latest_blockhash_with_commitment(CommitmentConfig::default())?; + let (blockhash, _last_height) = + rpc_client.get_latest_blockhash_with_commitment(CommitmentConfig::default())?; tx.sign(&config.signers, blockhash); debug!("sending tx: {:?}", tx); @@ -431,6 +467,11 @@ pub fn parse_evm_subcommand(matches: &ArgMatches<'_>) -> Result { + let input_path = value_t_or_exit!(matches, "input_path", PathBuf); + let schema_path = value_t_or_exit!(matches, "schema_path", PathBuf); + EvmCliCommand::GenerateBorshSchema { input_path, schema_path } + } ("send-raw-tx", Some(matches)) => { let raw_tx = value_t_or_exit!(matches, "raw_tx", PathBuf); EvmCliCommand::SendRawTx { raw_tx } diff --git a/evm-utils/programs/evm_loader/src/instructions/mod.rs b/evm-utils/programs/evm_loader/src/instructions/mod.rs index 4849bd13d4..40ee194ccc 100644 --- a/evm-utils/programs/evm_loader/src/instructions/mod.rs +++ b/evm-utils/programs/evm_loader/src/instructions/mod.rs @@ -1,5 +1,6 @@ +#![allow(dead_code)] use super::scope::*; -use borsh::{BorshDeserialize, BorshSerialize}; +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use evm_state::{Address, Transaction, UnsignedTransaction}; use serde::{Deserialize, Serialize}; @@ -10,8 +11,7 @@ pub const EVM_INSTRUCTION_BORSH_PREFIX: u8 = 255u8; #[derive( BorshSerialize, BorshDeserialize, - // TODO: add schema generation custom command - // BorshSchema, + BorshSchema, Clone, Debug, PartialEq, @@ -37,12 +37,10 @@ impl FeePayerType { /// Solana blockchain limit amount of data that transaction can have. /// To get around this limitation, we use design that is similar to LoaderInstruction in sdk. - #[derive( BorshSerialize, BorshDeserialize, - // TODO: add schema generation custom command - // BorshSchema, + BorshSchema, Clone, Debug, PartialEq, @@ -52,8 +50,6 @@ impl FeePayerType { Serialize, Deserialize, )] - -// #[allow(clippy::dead_code)] pub enum EvmBigTransaction { /// Allocate data in storage, pay fee should be taken from EVM. EvmTransactionAllocate { size: u64 }, @@ -65,8 +61,7 @@ pub enum EvmBigTransaction { #[derive( BorshSerialize, BorshDeserialize, - // TODO: add schema generation custom command - // BorshSchema, + BorshSchema, Clone, Debug, PartialEq, @@ -82,7 +77,7 @@ pub enum ExecuteTransaction { }, ProgramAuthorized { tx: Option, - from: evm::Address, + from: Address, }, } @@ -96,8 +91,7 @@ impl ExecuteTransaction { #[derive( BorshSerialize, BorshDeserialize, - // TODO: add schema generation custom command - // BorshSchema, + BorshSchema, Clone, Debug, PartialEq, @@ -122,7 +116,7 @@ pub enum EvmInstruction { /// SwapNativeToEther { lamports: u64, - evm_address: evm::Address, + evm_address: Address, }, /// Transfer user account ownership back to system program. @@ -285,9 +279,9 @@ mod test { #[derive(Clone, Debug)] struct Generator(T); - impl Arbitrary for Generator { + impl Arbitrary for Generator
{ fn arbitrary(g: &mut Gen) -> Self { - Generator(evm::Address::from_low_u64_ne(u64::arbitrary(g))) + Generator(Address::from_low_u64_ne(u64::arbitrary(g))) } } @@ -296,7 +290,7 @@ mod test { let action = if bool::arbitrary(g) { evm::TransactionAction::Create } else { - evm::TransactionAction::Call(evm::Address::from_low_u64_ne(u64::arbitrary(g))) + evm::TransactionAction::Call(Address::from_low_u64_ne(u64::arbitrary(g))) }; let tx = evm::UnsignedTransaction { nonce: evm::U256::from(u64::arbitrary(g)), @@ -315,7 +309,7 @@ mod test { let action = if bool::arbitrary(g) { evm::TransactionAction::Create } else { - evm::TransactionAction::Call(evm::Address::from_low_u64_ne(u64::arbitrary(g))) + evm::TransactionAction::Call(Address::from_low_u64_ne(u64::arbitrary(g))) }; let tx = evm::Transaction { nonce: evm::U256::from(u64::arbitrary(g)), @@ -335,8 +329,8 @@ mod test { } #[quickcheck] - fn test_serialize_swap_native_to_ether_layout(lamports: u64, addr: Generator) { - fn custom_serialize(lamports: u64, addr: evm::Address) -> Vec { + fn test_serialize_swap_native_to_ether_layout(lamports: u64, addr: Generator
) { + fn custom_serialize(lamports: u64, addr: Address) -> Vec { use byteorder::{LittleEndian, WriteBytesExt}; let tag: [u8; 4] = [1, 0, 0, 0]; @@ -397,14 +391,14 @@ mod test { #[quickcheck] fn test_serialize_unsigned_transaction( - addr: Generator, + addr: Generator
, tx: Generator, ) { let data = EvmInstruction::new_execute_authorized_tx(tx.0.clone(), addr.0, FeePayerType::Evm); fn custom_serialize( - from: evm::Address, + from: Address, nonce: evm::U256, gas_price: evm::U256, gas_limit: evm::U256,