use crate::runtime_group_tools::RuntimeGroup; use borsh::ser::BorshSerialize; use near_crypto::{InMemorySigner, KeyType}; use near_primitives::account::{AccessKeyPermission, FunctionCallPermission}; use near_primitives::hash::CryptoHash; use near_primitives::receipt::{ActionReceipt, ReceiptEnum}; pub mod runtime_group_tools; /// Initial balance used in tests. pub const TESTING_INIT_BALANCE: u128 = 1_000_000_000 * NEAR_BASE; /// One NEAR, divisible by 10^24. pub const NEAR_BASE: u128 = 1_000_000_000_000_000_000_000_000; const GAS_1: u64 = 900_000_000_000_000; const GAS_2: u64 = GAS_1 / 3; const GAS_3: u64 = GAS_2 / 3; #[test] fn test_simple_func_call() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(2, 2, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "sum_n".to_string(), args: 10u64.to_le_bytes().to_vec(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{..}), {} => [ref1] ); assert_refund!(group, ref1 @ "near_0"); } // single promise, no callback (A->B) #[test] fn test_single_promise_no_callback() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(3, 3, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"create": { "account_id": "near_2", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_2, }, "id": 0 } ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, ref0] ); assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [ref1]); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_0"); } // single promise with callback (A->B=>C) #[test] fn test_single_promise_with_callback() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(4, 4, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"create": { "account_id": "near_2", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_2, }, "id": 0 }, {"then": { "promise_index": 0, "account_id": "near_3", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_2, }, "id": 1} ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, r2, ref0] ); let data_id; assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, output_data_receivers, ..}), { assert_eq!(output_data_receivers.len(), 1); data_id = output_data_receivers[0].data_id.clone(); }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [ref1]); assert_receipts!(group, "near_1" => r2 @ "near_3", ReceiptEnum::Action(ActionReceipt{actions, input_data_ids, ..}), { assert_eq!(input_data_ids.len(), 1); assert_eq!(data_id, input_data_ids[0].clone()); }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [ref2]); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_0"); assert_refund!(group, ref2 @ "near_0"); } // two promises, no callbacks (A->B->C) #[test] fn test_two_promises_no_callbacks() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(4, 4, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"create": { "account_id": "near_2", "method_name": "call_promise", "arguments": [ {"create": { "account_id": "near_3", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_3, }, "id": 0} ], "amount": "0", "gas": GAS_2, }, "id": 0 }, ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, ref0] ); assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, ..}), { }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [r2, ref1]); assert_receipts!(group, "near_2" => r2 @ "near_3", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_3); assert_eq!(*deposit, 0); } => [ref2]); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_0"); assert_refund!(group, ref2 @ "near_0"); } // two promises, with two callbacks (A->B->C=>D=>E) where call to E is initialized by completion of D. #[test] fn test_two_promises_with_two_callbacks() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(6, 6, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"create": { "account_id": "near_2", "method_name": "call_promise", "arguments": [ {"create": { "account_id": "near_3", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_3, }, "id": 0}, {"then": { "promise_index": 0, "account_id": "near_4", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_3, }, "id": 1} ], "amount": "0", "gas": GAS_2, }, "id": 0 }, {"then": { "promise_index": 0, "account_id": "near_5", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_2, }, "id": 1} ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, cb1, ref0] ); assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, ..}), { }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [r2, cb2, ref1]); assert_receipts!(group, "near_2" => r2 @ "near_3", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_3); assert_eq!(*deposit, 0); } => [ref2]); assert_receipts!(group, "near_2" => cb2 @ "near_4", ReceiptEnum::Action(ActionReceipt{actions, ..}), { }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_3); assert_eq!(*deposit, 0); } => [ref3]); assert_receipts!(group, "near_1" => cb1 @ "near_5", ReceiptEnum::Action(ActionReceipt{actions, ..}), { }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [ref4]); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_0"); assert_refund!(group, ref2 @ "near_0"); assert_refund!(group, ref3 @ "near_0"); assert_refund!(group, ref4 @ "near_0"); } // Batch actions tests // single promise, no callback (A->B) with `promise_batch` #[test] fn test_single_promise_no_callback_batch() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(3, 3, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"batch_create": { "account_id": "near_2", }, "id": 0 }, {"action_function_call": { "promise_index": 0, "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_2, }, "id": 0 } ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, ref0] ); assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [ref1]); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_0"); } // single promise with callback (A->B=>C) with batch actions #[test] fn test_single_promise_with_callback_batch() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(4, 4, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"batch_create": { "account_id": "near_2", }, "id": 0 }, {"action_function_call": { "promise_index": 0, "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_2, }, "id": 0 }, {"batch_then": { "promise_index": 0, "account_id": "near_3", }, "id": 1}, {"action_function_call": { "promise_index": 1, "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_2, }, "id": 1} ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, r2, ref0] ); let data_id; assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, output_data_receivers, ..}), { assert_eq!(output_data_receivers.len(), 1); data_id = output_data_receivers[0].data_id.clone(); }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [ref1]); assert_receipts!(group, "near_1" => r2 @ "near_3", ReceiptEnum::Action(ActionReceipt{actions, input_data_ids, ..}), { assert_eq!(input_data_ids.len(), 1); assert_eq!(data_id, input_data_ids[0].clone()); }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [ref2]); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_0"); assert_refund!(group, ref2 @ "near_0"); } #[test] fn test_simple_transfer() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(3, 3, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"batch_create": { "account_id": "near_2", }, "id": 0 }, {"action_transfer": { "promise_index": 0, "amount": "1000000000", }, "id": 0 } ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, ref0] ); assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::Transfer(TransferAction{deposit}), { assert_eq!(*deposit, 1000000000); } => [ref1] ); assert_refund!(group, ref0 @ "near_0"); // For gas price difference assert_refund!(group, ref1 @ "near_0"); } #[test] fn test_create_account_with_transfer_and_full_key() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(3, 2, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let signer_new_account = group.signers[2].clone(); let data = serde_json::json!([ {"batch_create": { "account_id": "near_2", }, "id": 0 }, {"action_create_account": { "promise_index": 0, }, "id": 0 }, {"action_transfer": { "promise_index": 0, "amount": "10000000000000000000000000", }, "id": 0 }, {"action_add_key_with_full_access": { "promise_index": 0, "public_key": base64::encode(&signer_new_account.public_key.try_to_vec().unwrap()), "nonce": 0, }, "id": 0 } ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, ref0] ); assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::CreateAccount(CreateAccountAction{}), {}, a1, Action::Transfer(TransferAction{deposit}), { assert_eq!(*deposit, 10000000000000000000000000); }, a2, Action::AddKey(AddKeyAction{public_key, access_key}), { assert_eq!(public_key, &signer_new_account.public_key); assert_eq!(access_key.nonce, 0); assert_eq!(access_key.permission, AccessKeyPermission::FullAccess); } => [ref1] ); assert_refund!(group, ref0 @ "near_0"); // For gas price difference assert_refund!(group, ref1 @ "near_0"); } #[test] fn test_account_factory() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(3, 2, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let signer_new_account = group.signers[2].clone(); let data = serde_json::json!([ {"batch_create": { "account_id": "near_2", }, "id": 0 }, {"action_create_account": { "promise_index": 0, }, "id": 0 }, {"action_transfer": { "promise_index": 0, "amount": format!("{}", TESTING_INIT_BALANCE / 2), }, "id": 0 }, {"action_add_key_with_function_call": { "promise_index": 0, "public_key": base64::encode(&signer_new_account.public_key.try_to_vec().unwrap()), "nonce": 0, "allowance": format!("{}", TESTING_INIT_BALANCE / 2), "receiver_id": "near_1", "method_names": "call_promise,hello" }, "id": 0 }, {"action_deploy_contract": { "promise_index": 0, "code": base64::encode(wasm_binary), }, "id": 0 }, {"action_function_call": { "promise_index": 0, "method_name": "call_promise", "arguments": [ {"create": { "account_id": "near_0", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_3, }, "id": 0} ], "amount": "0", "gas": GAS_2, }, "id": 0 }, {"then": { "promise_index": 0, "account_id": "near_2", "method_name": "call_promise", "arguments": [ {"create": { "account_id": "near_1", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_3, }, "id": 0} ], "amount": "0", "gas": GAS_2, }, "id": 1} ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, r2, ref0] ); let data_id; assert_receipts!(group, "near_1" => r1 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, output_data_receivers, ..}), { assert_eq!(output_data_receivers.len(), 1); data_id = output_data_receivers[0].data_id.clone(); assert_eq!(&output_data_receivers[0].receiver_id, "near_2"); }, actions, a0, Action::CreateAccount(CreateAccountAction{}), {}, a1, Action::Transfer(TransferAction{deposit}), { assert_eq!(*deposit, TESTING_INIT_BALANCE / 2); }, a2, Action::AddKey(AddKeyAction{public_key, access_key}), { assert_eq!(public_key, &signer_new_account.public_key); assert_eq!(access_key.nonce, 0); assert_eq!(access_key.permission, AccessKeyPermission::FunctionCall(FunctionCallPermission { allowance: Some(TESTING_INIT_BALANCE / 2), receiver_id: "near_1".to_string(), method_names: vec!["call_promise".to_string(), "hello".to_string()], })); }, a3, Action::DeployContract(DeployContractAction{code}), { assert_eq!(code, &wasm_binary); }, a4, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [r3, ref1] ); assert_receipts!(group, "near_1" => r2 @ "near_2", ReceiptEnum::Action(ActionReceipt{actions, input_data_ids, ..}), { assert_eq!(input_data_ids, &vec![data_id]); }, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); } => [r4, ref2] ); assert_receipts!(group, "near_2" => r3 @ "near_0", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_3); assert_eq!(*deposit, 0); } => [ref3] ); assert_receipts!(group, "near_2" => r4 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_3); assert_eq!(*deposit, 0); } => [ref4] ); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_0"); assert_refund!(group, ref2 @ "near_0"); assert_refund!(group, ref3 @ "near_0"); assert_refund!(group, ref4 @ "near_0"); } #[test] fn test_create_account_add_key_call_delete_key_delete_account() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let group = RuntimeGroup::new(4, 3, wasm_binary); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let signer_new_account = group.signers[2].clone(); let data = serde_json::json!([ {"batch_create": { "account_id": "near_3", }, "id": 0 }, {"action_create_account": { "promise_index": 0, }, "id": 0 }, {"action_transfer": { "promise_index": 0, "amount": format!("{}", TESTING_INIT_BALANCE / 2), }, "id": 0 }, {"action_add_key_with_full_access": { "promise_index": 0, "public_key": base64::encode(&signer_new_account.public_key.try_to_vec().unwrap()), "nonce": 1, }, "id": 0 }, {"action_deploy_contract": { "promise_index": 0, "code": base64::encode(wasm_binary), }, "id": 0 }, {"action_function_call": { "promise_index": 0, "method_name": "call_promise", "arguments": [ {"create": { "account_id": "near_0", "method_name": "call_promise", "arguments": [], "amount": "0", "gas": GAS_3, }, "id": 0} ], "amount": "0", "gas": GAS_2, }, "id": 0 }, {"action_delete_key": { "promise_index": 0, "public_key": base64::encode(&signer_new_account.public_key.try_to_vec().unwrap()), "nonce": 0, }, "id": 0 }, {"action_delete_account": { "promise_index": 0, "beneficiary_id": "near_2" }, "id": 0 }, ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, ref0] ); assert_receipts!(group, "near_1" => r1 @ "near_3", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::CreateAccount(CreateAccountAction{}), {}, a1, Action::Transfer(TransferAction{deposit}), { assert_eq!(*deposit, TESTING_INIT_BALANCE / 2); }, a2, Action::AddKey(AddKeyAction{public_key, access_key}), { assert_eq!(public_key, &signer_new_account.public_key); assert_eq!(access_key.nonce, 1); assert_eq!(access_key.permission, AccessKeyPermission::FullAccess); }, a3, Action::DeployContract(DeployContractAction{code}), { assert_eq!(code, &wasm_binary); }, a4, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_2); assert_eq!(*deposit, 0); }, a5, Action::DeleteKey(DeleteKeyAction{public_key}), { assert_eq!(public_key, &signer_new_account.public_key); }, a6, Action::DeleteAccount(DeleteAccountAction{beneficiary_id}), { assert_eq!(beneficiary_id.as_str(), "near_2"); } => [r2, ref1, ref2] ); assert_receipts!(group, "near_3" => r2 @ "near_0", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_3); assert_eq!(*deposit, 0); } => [ref3] ); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_2"); assert_refund!(group, ref2 @ "near_0"); assert_refund!(group, ref3 @ "near_0"); } #[test] fn test_transfer_64len_hex() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let pk = InMemorySigner::from_seed("test_hex", KeyType::ED25519, "test_hex"); let account_id = hex::encode(pk.public_key.unwrap_as_ed25519().0); let group = RuntimeGroup::new_with_account_ids( vec!["near_0".to_string(), "near_1".to_string(), account_id.clone()], 2, wasm_binary, ); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"batch_create": { "account_id": account_id, }, "id": 0 }, {"action_transfer": { "promise_index": 0, "amount": format!("{}", TESTING_INIT_BALANCE / 2), }, "id": 0 }, ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, ref0] ); assert_receipts!(group, "near_1" => r1 @ &account_id, ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::Transfer(TransferAction{deposit}), { assert_eq!(*deposit, TESTING_INIT_BALANCE / 2); } => [ref1] ); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_0"); } #[test] fn test_create_transfer_64len_hex_fail() { let wasm_binary: &[u8] = include_bytes!("../../near-vm-runner/tests/res/test_contract_rs.wasm"); let pk = InMemorySigner::from_seed("test_hex", KeyType::ED25519, "test_hex"); let account_id = hex::encode(pk.public_key.unwrap_as_ed25519().0); let group = RuntimeGroup::new_with_account_ids( vec!["near_0".to_string(), "near_1".to_string(), account_id.clone()], 2, wasm_binary, ); let signer_sender = group.signers[0].clone(); let signer_receiver = group.signers[1].clone(); let data = serde_json::json!([ {"batch_create": { "account_id": account_id, }, "id": 0 }, {"action_create_account": { "promise_index": 0, }, "id": 0 }, {"action_transfer": { "promise_index": 0, "amount": format!("{}", TESTING_INIT_BALANCE / 2), }, "id": 0 }, ]); let signed_transaction = SignedTransaction::from_actions( 1, signer_sender.account_id.clone(), signer_receiver.account_id.clone(), &signer_sender, vec![Action::FunctionCall(FunctionCallAction { method_name: "call_promise".to_string(), args: serde_json::to_vec(&data).unwrap(), gas: GAS_1, deposit: 0, })], CryptoHash::default(), ); let handles = RuntimeGroup::start_runtimes(group.clone(), vec![signed_transaction.clone()]); for h in handles { h.join().unwrap(); } use near_primitives::transaction::*; assert_receipts!(group, signed_transaction => [r0]); assert_receipts!(group, "near_0" => r0 @ "near_1", ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::FunctionCall(FunctionCallAction{gas, deposit, ..}), { assert_eq!(*gas, GAS_1); assert_eq!(*deposit, 0); } => [r1, ref0] ); assert_receipts!(group, "near_1" => r1 @ &account_id, ReceiptEnum::Action(ActionReceipt{actions, ..}), {}, actions, a0, Action::CreateAccount(CreateAccountAction{}), {}, a1, Action::Transfer(TransferAction{deposit}), { assert_eq!(*deposit, TESTING_INIT_BALANCE / 2); } => [ref1, ref2] ); assert_refund!(group, ref0 @ "near_0"); assert_refund!(group, ref1 @ "near_1"); assert_refund!(group, ref2 @ "near_0"); }