diff --git a/.github/workflows/release_asset.yml b/.github/workflows/release_asset.yml new file mode 100644 index 0000000000..02fd808a39 --- /dev/null +++ b/.github/workflows/release_asset.yml @@ -0,0 +1,59 @@ +name: Release asset bot + +on: + workflow_dispatch: + release: + types: [published] +jobs: + build: + name: Build release asset + continue-on-error: true + strategy: + fail-fast: false + matrix: + platform: + - ubuntu-latest + - ubuntu-18.04 + - ubuntu-22.04 + - macos-latest + - windows-latest + runs-on: ${{matrix.platform}} + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Install LLVM and Clang # required for bindgen to work, see https://github.com/rust-lang/rust-bindgen/issues/1797 + uses: KyleMayes/install-llvm-action@v1 + if: matrix.platform == 'windows-latest' + with: + version: "11.0" + directory: ${{ runner.temp }}/llvm + - name: Set LIBCLANG_PATH + run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV + if: matrix.platform == 'windows-latest' + - name: build for ${{ matrix.platform }} + uses: actions-rs/cargo@v1 + with: + command: build + args: --release + + - name: build rooch release asset + run: bash ./scripts/release.sh ${{ matrix.platform }} + + - name: upload artifact asset + uses: actions/upload-artifact@v2 + if: ${{ github.event_name != 'release'}} + with: + name: rooch-${{ matrix.platform }}.zip + path: ./rooch-${{ matrix.platform }}.zip + + - name: upload rooch release asset + if: ${{ github.event_name == 'release'}} + id: upload-release-asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./rooch-${{ matrix.platform }}.zip + asset_name: rooch-${{ matrix.platform }}.zip + asset_content_type: application/zip diff --git a/crates/rooch-executor/src/actor/executor.rs b/crates/rooch-executor/src/actor/executor.rs index 02550442b1..c2a8cead5c 100644 --- a/crates/rooch-executor/src/actor/executor.rs +++ b/crates/rooch-executor/src/actor/executor.rs @@ -3,14 +3,15 @@ use super::messages::{ AnnotatedStatesMessage, ExecuteTransactionMessage, ExecuteTransactionResult, - ExecuteViewFunctionMessage, GetEventsByEventHandleMessage, GetEventsMessage, StatesMessage, - ValidateTransactionMessage, + ExecuteViewFunctionMessage, GetEventsByEventHandleMessage, GetEventsMessage, ResolveMessage, + StatesMessage, ValidateTransactionMessage, }; use crate::actor::messages::{GetTransactionInfosByTxHashMessage, GetTxSeqMappingByTxOrderMessage}; use anyhow::bail; use anyhow::Result; use async_trait::async_trait; use coerce::actor::{context::ActorContext, message::Handler, Actor}; +use move_core_types::account_address::AccountAddress; use move_resource_viewer::MoveValueAnnotator; use moveos::moveos::MoveOS; use moveos_common::accumulator::InMemoryAccumulator; @@ -28,6 +29,7 @@ use rooch_framework::bindings::address_mapping::AddressMapping; use rooch_framework::bindings::transaction_validator::TransactionValidator; use rooch_genesis::RoochGenesis; use rooch_store::RoochDB; +use rooch_types::address::MultiChainAddress; use rooch_types::transaction::{AbstractTransaction, TransactionSequenceMapping}; pub struct ExecutorActor { @@ -47,9 +49,10 @@ impl ExecutorActor { Ok(Self { moveos, rooch_db }) } - pub fn validate(&self, tx: T) -> Result { - let multi_chain_address_sender = tx.sender(); - + pub fn resolve_address( + &self, + multi_chain_address_sender: MultiChainAddress, + ) -> Result { let resolved_sender = { let address_mapping = self.moveos.as_module_bundle::(); address_mapping @@ -61,9 +64,17 @@ impl ExecutorActor { ) })? }; + + Ok(resolved_sender) + } + + pub fn validate(&self, tx: T) -> Result { + let multi_chain_address_sender = tx.sender(); + + let resolved_sender = self.resolve_address(multi_chain_address_sender.clone()); let authenticator = tx.authenticator_info(); - let mut moveos_tx = tx.construct_moveos_transaction(resolved_sender)?; + let mut moveos_tx = tx.construct_moveos_transaction(resolved_sender?)?; let result = { let tx_validator = self.moveos.as_module_bundle::(); @@ -159,6 +170,17 @@ impl Handler for ExecutorActor { } } +#[async_trait] +impl Handler for ExecutorActor { + async fn handle( + &mut self, + msg: ResolveMessage, + _ctx: &mut ActorContext, + ) -> Result { + self.resolve_address(msg.address) + } +} + #[async_trait] impl Handler for ExecutorActor { async fn handle( diff --git a/crates/rooch-executor/src/actor/messages.rs b/crates/rooch-executor/src/actor/messages.rs index 04eb98a4cc..3d20347d7d 100644 --- a/crates/rooch-executor/src/actor/messages.rs +++ b/crates/rooch-executor/src/actor/messages.rs @@ -3,6 +3,7 @@ use anyhow::Result; use coerce::actor::message::Message; +use move_core_types::account_address::AccountAddress; use move_core_types::language_storage::StructTag; use moveos_types::access_path::AccessPath; use moveos_types::event::AnnotatedMoveOSEvent; @@ -14,6 +15,7 @@ use moveos_types::transaction::FunctionCall; use moveos_types::transaction::TransactionExecutionInfo; use moveos_types::transaction::TransactionOutput; use moveos_types::transaction::VerifiedMoveOSTransaction; +use rooch_types::address::MultiChainAddress; use rooch_types::transaction::{AbstractTransaction, TransactionSequenceMapping}; use serde::{Deserialize, Serialize}; @@ -61,6 +63,15 @@ impl Message for StatesMessage { type Result = Result>>; } +#[derive(Debug, Serialize, Deserialize)] +pub struct ResolveMessage { + pub address: MultiChainAddress, +} + +impl Message for ResolveMessage { + type Result = Result; +} + #[derive(Debug, Serialize, Deserialize)] pub struct AnnotatedStatesMessage { pub access_path: AccessPath, diff --git a/crates/rooch-executor/src/proxy/mod.rs b/crates/rooch-executor/src/proxy/mod.rs index 75d8a61b22..0c13c7dc5a 100644 --- a/crates/rooch-executor/src/proxy/mod.rs +++ b/crates/rooch-executor/src/proxy/mod.rs @@ -6,11 +6,12 @@ use crate::actor::{ executor::ExecutorActor, messages::{ AnnotatedStatesMessage, ExecuteViewFunctionMessage, GetEventsByEventHandleMessage, - GetEventsMessage, StatesMessage, ValidateTransactionMessage, + GetEventsMessage, ResolveMessage, StatesMessage, ValidateTransactionMessage, }, }; use anyhow::Result; use coerce::actor::ActorRef; +use move_core_types::account_address::AccountAddress; use move_core_types::language_storage::StructTag; use moveos_types::h256::H256; use moveos_types::transaction::FunctionCall; @@ -25,6 +26,7 @@ use moveos_types::{ event_filter::EventFilter, state::{AnnotatedState, State}, }; +use rooch_types::address::MultiChainAddress; use rooch_types::transaction::{AbstractTransaction, TransactionSequenceMapping}; #[derive(Clone)] @@ -67,6 +69,10 @@ impl ExecutorProxy { self.actor.send(StatesMessage { access_path }).await? } + pub async fn resolve_address(&self, mca: MultiChainAddress) -> Result { + self.actor.send(ResolveMessage { address: mca }).await? + } + pub async fn get_annotated_states( &self, access_path: AccessPath, diff --git a/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_invalid_struct.exp b/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_invalid_struct.exp index f515f97fd9..8086a1fda1 100644 --- a/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_invalid_struct.exp +++ b/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_invalid_struct.exp @@ -1,11 +1,11 @@ processed 2 tasks task 1 'publish'. lines 3-12: -error: type `test::Foo` is not supported as a parameter type +Error: error: type `test::Foo` is not supported as a parameter type ┌─ /tmp/tempfile:8:5 │ 8 │ ╭ entry public fun test_entry_function_invalid_struct( _foo: Foo ){ 9 │ │ } │ ╰─────^ -status EXECUTED + diff --git a/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_valid_reference.exp b/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_valid_reference.exp index 359906d79f..58d5157a31 100644 --- a/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_valid_reference.exp +++ b/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_valid_reference.exp @@ -1,11 +1,11 @@ processed 2 tasks task 1 'publish'. lines 3-33: -error: type `&mut signer` is not supported as a parameter type +Error: error: type `&mut signer` is not supported as a parameter type ┌─ /tmp/tempfile:9:5 │ 9 │ ╭ entry public fun test_entry_function_valid_reference_mut_signer( _: &mut signer ){ 10 │ │ } │ ╰─────^ -status EXECUTED + diff --git a/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_with_return_value.exp b/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_with_return_value.exp index b3471da363..ae453d17a8 100644 --- a/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_with_return_value.exp +++ b/crates/rooch-framework-tests/tests/cases/entry_function/entry_function_with_return_value.exp @@ -1,7 +1,7 @@ processed 2 tasks task 1 'publish'. lines 3-54: -error: entry function cannot return values +Error: error: entry function cannot return values ┌─ /tmp/tempfile:26:5 │ 26 │ ╭ entry public fun test_entry_function_return_value_String():std::string::String{ @@ -81,4 +81,4 @@ error: entry function cannot return values 7 │ │ } │ ╰─────^ -status EXECUTED + diff --git a/crates/rooch-framework-tests/tests/cases/object/object_cap.exp b/crates/rooch-framework-tests/tests/cases/object/object_cap.exp index 2dfb542c44..9c86187cd4 100644 --- a/crates/rooch-framework-tests/tests/cases/object/object_cap.exp +++ b/crates/rooch-framework-tests/tests/cases/object/object_cap.exp @@ -4,7 +4,7 @@ task 1 'publish'. lines 3-21: status EXECUTED task 2 'run'. lines 22-38: -error: resource type "TestObject" in function "0x2::object::new" not defined in current module or not allowed +Error: error: resource type "TestObject" in function "0x2::object::new" not defined in current module or not allowed ┌─ /tmp/tempfile:31:19 │ 31 │ let obj = object::new(storage_context::tx_context_mut(ctx), sender_addr, object); @@ -22,4 +22,4 @@ error: resource type "TestObject" in function "0x2::object::unpack" not defined 33 │ let (_id, _owner, test_object) = object::unpack(obj); │ ^^^^^^^^^^^^^^^^^^^ -status EXECUTED + diff --git a/crates/rooch-framework/doc/address_mapping.md b/crates/rooch-framework/doc/address_mapping.md index 4412ab9173..1ddd4db6d7 100644 --- a/crates/rooch-framework/doc/address_mapping.md +++ b/crates/rooch-framework/doc/address_mapping.md @@ -23,6 +23,7 @@ use 0x2::table; use 0x2::tx_context; use 0x3::core_addresses; +use 0x3::rooch_hash; @@ -168,7 +169,7 @@ Resolve a multi-chain address to a rooch address let addr = table::borrow(&am.mapping, maddress); option::some(*addr) }else{ - option::none<address>() + default_rooch_address(maddress) } } diff --git a/crates/rooch-framework/sources/account.move b/crates/rooch-framework/sources/account.move index d562e1a981..553356f899 100644 --- a/crates/rooch-framework/sources/account.move +++ b/crates/rooch-framework/sources/account.move @@ -339,7 +339,7 @@ module rooch_framework::account{ #[test(sender=@0x0)] #[expected_failure(abort_code = 0x10005, location = Self)] - fun test_failur_entry_account_creation_reserved(sender: address){ + fun test_failure_entry_account_creation_reserved(sender: address){ let ctx = storage_context::new_test_context(sender); create_account_entry(&mut ctx, sender); storage_context::drop_test_context(ctx); diff --git a/crates/rooch-framework/sources/address_mapping.move b/crates/rooch-framework/sources/address_mapping.move index 8d18659c60..7d9e8ef00a 100644 --- a/crates/rooch-framework/sources/address_mapping.move +++ b/crates/rooch-framework/sources/address_mapping.move @@ -5,6 +5,7 @@ module rooch_framework::address_mapping{ use moveos_std::storage_context::{Self, StorageContext}; use moveos_std::table::{Self, Table}; use moveos_std::account_storage; + use rooch_framework::rooch_hash::{blake2b256}; friend rooch_framework::transaction_validator; @@ -46,10 +47,15 @@ module rooch_framework::address_mapping{ let addr = table::borrow(&am.mapping, maddress); option::some(*addr) }else{ - option::none
() + default_rooch_address(maddress) } } + fun default_rooch_address(maddress: MultiChainAddress): Option
{ + let hash = blake2b256(&maddress.raw_address); + option::some(moveos_std::bcd::to_address(hash)) + } + /// Check if a multi-chain address is bound to a rooch address public fun exists_mapping(ctx: &StorageContext, maddress: MultiChainAddress): bool { if (is_rooch_address(&maddress)) { diff --git a/crates/rooch-integration-test-runner/tests/cases/private_generics_indirect_call.exp b/crates/rooch-integration-test-runner/tests/cases/private_generics_indirect_call.exp index 01f5912fda..2b0ab1c6fa 100644 --- a/crates/rooch-integration-test-runner/tests/cases/private_generics_indirect_call.exp +++ b/crates/rooch-integration-test-runner/tests/cases/private_generics_indirect_call.exp @@ -4,7 +4,7 @@ task 1 'publish'. lines 3-8: status EXECUTED task 2 'publish'. lines 10-48: -error: resource type "KeyStruct" in function "0x2::object_storage::remove" not defined in current module or not allowed +Error: error: resource type "KeyStruct" in function "0x2::object_storage::remove" not defined in current module or not allowed ┌─ /tmp/tempfile:37:19 │ 37 │ let obj = object_storage::remove(object_storage, object_id); @@ -22,4 +22,4 @@ error: resource type "KeyStruct" in function "0x2::account_storage::global_move_ 40 │ account_storage::global_move_to(ctx, &sender, value); │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -status EXECUTED + diff --git a/crates/rooch-server/src/api/eth_api.rs b/crates/rooch-server/src/api/eth_api.rs index 5c8ae10d5c..ddb3731096 100644 --- a/crates/rooch-server/src/api/eth_api.rs +++ b/crates/rooch-server/src/api/eth_api.rs @@ -3,7 +3,8 @@ use crate::jsonrpc_types::eth::{CallRequest, EthFeeHistory}; use ethers::types::{ - Block, BlockNumber, Bytes, Transaction, TransactionRequest, TxHash, H160, U256, + Block, BlockNumber, Bytes, Transaction, TransactionReceipt, TransactionRequest, TxHash, H160, + U256, }; use jsonrpsee::core::RpcResult; use jsonrpsee::proc_macros::rpc; @@ -87,4 +88,20 @@ pub trait EthAPI { /// Sends signed transaction, returning its hash. #[method(name = "eth_sendRawTransaction")] async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult; + + /// Returns transaction receipt by transaction hash. + #[method(name = "eth_getTransactionReceipt")] + async fn transaction_receipt(&self, hash: H256) -> RpcResult>; + + /// Get transaction by its hash. + #[method(name = "eth_getTransactionByHash")] + async fn transaction_by_hash(&self, hash: H256) -> RpcResult>; + + /// Returns block with given hash. + #[method(name = "eth_getBlockByHash")] + async fn block_by_hash( + &self, + hash: H256, + include_txs: bool, + ) -> RpcResult>; } diff --git a/crates/rooch-server/src/server/eth_server.rs b/crates/rooch-server/src/server/eth_server.rs index 73f7a9a1f1..0c9cb0ed3a 100644 --- a/crates/rooch-server/src/server/eth_server.rs +++ b/crates/rooch-server/src/server/eth_server.rs @@ -1,7 +1,10 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -use crate::jsonrpc_types::eth::{CallRequest, EthFeeHistory}; +use crate::jsonrpc_types::{ + eth::{CallRequest, EthFeeHistory}, + TransactionView, +}; use crate::{ api::{ eth_api::{EthAPIServer, TransactionType}, @@ -10,16 +13,18 @@ use crate::{ service::RpcService, }; use ethers::types::{ - transaction::eip2930::AccessList, Block, BlockNumber, Bytes, OtherFields, Transaction, - Withdrawal, H160, U256, U64, + transaction::eip2930::AccessList, Address, Block, BlockNumber, Bloom, Bytes, OtherFields, + Transaction, TransactionReceipt, Withdrawal, H160, U256, U64, }; use jsonrpsee::{ core::{async_trait, Error as JsonRpcError, RpcResult}, RpcModule, }; -use rand::rngs::StdRng; -use rand::{Rng, SeedableRng}; +use moveos_types::{access_path::AccessPath, state::MoveStructType}; +use rand::Rng; use rooch_types::{ + account::Account, + address::{EthereumAddress, MultiChainAddress}, transaction::{ethereum::EthereumTransaction, AbstractTransaction, TypedTransaction}, H256, }; @@ -240,13 +245,21 @@ impl EthAPIServer for EthServer { Ok(U256::from(20 * (10_u64.pow(9)))) } - async fn transaction_count( - &self, - _address: H160, - _num: Option, - ) -> RpcResult { - let mut rng = StdRng::from_entropy(); - Ok(U256::from(rng.gen_range(0..10000))) + async fn transaction_count(&self, address: H160, _num: Option) -> RpcResult { + let account_address = self + .rpc_service + .resolve_address(MultiChainAddress::from(EthereumAddress(address))) + .await?; + + Ok(self + .rpc_service + .get_states(AccessPath::resource(account_address, Account::struct_tag())) + .await? + .pop() + .flatten() + .map(|state_view| state_view.as_move_state::()) + .transpose()? + .map_or(0.into(), |account| account.sequence_number.into())) } async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult { @@ -258,12 +271,185 @@ impl EthAPIServer for EthServer { "send_raw_transaction decode_calldata_to_action: {:?}", action ); + info!("send_raw_transaction nonce: {:?}", eth_tx.0.nonce); let tx = TypedTransaction::Ethereum(eth_tx); let hash = tx.tx_hash(); let _output = self.rpc_service.execute_tx(tx).await?; Ok(hash) } + + async fn transaction_receipt(&self, hash: H256) -> RpcResult> { + let result = self + .rpc_service + .get_transaction_infos_by_tx_hash(vec![hash]) + .await? + .into_iter() + .last() + .and_then(|trans| { + trans.map(|info| TransactionReceipt { + transaction_hash: info.tx_hash, + block_hash: Some(info.state_root), + block_number: Some(10_u64.into()), + gas_used: Some(info.gas_used.into()), + status: Some((info.status.is_success() as u8).into()), + cumulative_gas_used: info.gas_used.into(), + contract_address: None, + logs: Vec::new(), + logs_bloom: Bloom::default(), + ..Default::default() + }) + }); + + Ok(result) + } + + async fn transaction_by_hash(&self, hash: H256) -> RpcResult> { + let resp = self + .rpc_service + .get_transaction_by_hash(hash) + .await? + .map(Into::into); + + let transaction = resp.map(|_transaction_view: TransactionView| -> Transaction { + Transaction { + hash: H256::from_str("0x7fd17d4a368fccdba4291ab121e48c96329b7dc3d027a373643fb23c20a19a3f").unwrap(), + nonce: U256::from(4391989), + block_hash: Some(H256::from_str("0xc2794a16acacd9f7670379ffd12b6968ff98e2a602f57d7d1f880220aa5a4973").unwrap()), + block_number: Some(8453214u64.into()), + transaction_index: Some(0u64.into()), + from: Address::from_str("0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001").unwrap(), + to: Some(Address::from_str("0x4200000000000000000000000000000000000015").unwrap()), + value: U256::zero(), + gas_price: Some(U256::zero()), + gas: U256::from(1000000u64), + input: Bytes::from( + hex::decode("015d8eb90000000000000000000000000000000000000000000000000000000000878c1c00000000000000000000000000000000000000000000000000000000644662bc0000000000000000000000000000000000000000000000000000001ee24fba17b7e19cc10812911dfa8a438e0a81a9933f843aa5b528899b8d9e221b649ae0df00000000000000000000000000000000000000000000000000000000000000060000000000000000000000007431310e026b69bfc676c0013e12a1a11411eec9000000000000000000000000000000000000000000000000000000000000083400000000000000000000000000000000000000000000000000000000000f4240").unwrap() + ), + v: U64::zero(), + r: U256::zero(), + s: U256::zero(), + transaction_type: Some(U64::from(126)), + access_list: None, + max_priority_fee_per_gas: None, + max_fee_per_gas: None, + chain_id: None, + other: Default::default() + } + }); + + Ok(transaction) + } + + async fn block_by_hash( + &self, + hash: H256, + include_txs: bool, + ) -> RpcResult> { + let block_number = 10_u64.into(); + let parent_hash = "0xe5ece23ec875db0657f964cbc74fa34439eef3ab3dc8664e7f4ae8b5c5c963e1" + .parse() + .unwrap(); + let gas_limit = U256::from_str("0x1c9c380").unwrap(); + let gas_used = U256::from_str("0xf4954d").unwrap(); + + let txs = if include_txs { + vec![TransactionType::Full(Transaction { + hash, + nonce: U256::zero(), + block_hash: Some(parent_hash), + block_number: Some(block_number), + transaction_index: Some(U64::from(0)), + from: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e" + .parse() + .unwrap(), + to: Some( + "0x832daF8DDe81fA5186EF2D04b3099251c508D5A1" + .parse() + .unwrap(), + ), + value: U256::from(1_000_000), + gas_price: Some(U256::from(20_000_000_000u64)), + gas: U256::from(21_000), + input: vec![].into(), + r: U256::zero(), + s: U256::zero(), + v: U64::one(), + transaction_type: Default::default(), + access_list: Some(AccessList::default()), + max_priority_fee_per_gas: Default::default(), + max_fee_per_gas: Default::default(), + chain_id: Some(U256::from(10001)), + other: OtherFields::default(), + })] + } else { + vec![TransactionType::Hash( + "0x96c133e6ee7966ee28e6a3b4abd38d1feb15bfcb9e3a36257bd4818ad679c26e" + .parse() + .unwrap(), + )] + }; + + let block = Block { + hash: Some( + "0xa4161cc321054df6e370776f19a958950ce4237fca4aff57605efdcdd3b802f4" + .parse() + .unwrap(), + ), + parent_hash, + uncles_hash: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + .parse() + .unwrap(), + author: Some( + "0xbaf6dc2e647aeb6f510f9e318856a1bcd66c5e19" + .parse() + .unwrap(), + ), + state_root: "0xde1cdf9816313c105a75eaaedab04815b1b7aa5650bf91b69749d71a36497243" + .parse() + .unwrap(), + transactions_root: "0xdc8c2a8825fbbe669360d351e34f3ad09d320db83539c98e92bb18ea5fa93773" + .parse() + .unwrap(), + receipts_root: "0x31814320e99d27d63448b25b122870e70427d8261bbaa3674e96dd686bcb507a" + .parse() + .unwrap(), + number: Some(block_number), + gas_used, + gas_limit, + extra_data: Bytes::from_str( + "0x4d616465206f6e20746865206d6f6f6e20627920426c6f636b6e6174697665", + ) + .unwrap(), + logs_bloom: None, + timestamp: U256::from_str("0x64731653").unwrap(), + difficulty: U256::zero(), + total_difficulty: Some(U256::from_str("0xc70d815d562d3cfa955").unwrap()), + seal_fields: vec![], + uncles: vec![], + transactions: txs, + size: None, + mix_hash: None, + nonce: None, + base_fee_per_gas: Some(U256::from_str("0x52e0ce91c").unwrap()), + withdrawals_root: Some( + "0xdc8c2a8825fbbe669360d351e34f3ad09d320db83539c98e92bb18ea5fa93773" + .parse() + .unwrap(), + ), + withdrawals: Some(vec![Withdrawal { + address: "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f" + .parse() + .unwrap(), + amount: U256::from_str("0xc7a3fa").unwrap(), + index: U64::from_str("0x4e81dc").unwrap(), + validator_index: U64::from_str("0x5be41").unwrap(), + }]), + other: OtherFields::default(), + }; + + Ok(block) + } } impl RoochRpcModule for EthServer { diff --git a/crates/rooch-server/src/service/mod.rs b/crates/rooch-server/src/service/mod.rs index b78f5ebe11..7eccde37f9 100644 --- a/crates/rooch-server/src/service/mod.rs +++ b/crates/rooch-server/src/service/mod.rs @@ -3,6 +3,7 @@ use crate::jsonrpc_types::ExecuteTransactionResponse; use anyhow::{bail, Result}; +use move_core_types::account_address::AccountAddress; use move_core_types::language_storage::StructTag; use moveos_types::access_path::AccessPath; use moveos_types::event::AnnotatedMoveOSEvent; @@ -13,8 +14,9 @@ use moveos_types::transaction::{FunctionCall, TransactionExecutionInfo}; use rooch_executor::proxy::ExecutorProxy; use rooch_proposer::proxy::ProposerProxy; use rooch_sequencer::proxy::SequencerProxy; +use rooch_types::address::{MultiChainAddress, RoochAddress}; use rooch_types::transaction::TransactionSequenceMapping; -use rooch_types::{address::RoochAddress, transaction::TypedTransaction, H256}; +use rooch_types::{transaction::TypedTransaction, H256}; /// RpcService is the implementation of the RPC service. /// It is the glue between the RPC server(EthAPIServer,RoochApiServer) and the rooch's actors. @@ -72,6 +74,10 @@ impl RpcService { Ok(resp) } + pub async fn resolve_address(&self, mca: MultiChainAddress) -> Result { + self.executor.resolve_address(mca).await + } + pub async fn get_states(&self, access_path: AccessPath) -> Result>> { self.executor.get_states(access_path).await } diff --git a/crates/rooch/src/commands/init.rs b/crates/rooch/src/commands/init.rs index 17818bfe89..08e293bb5a 100644 --- a/crates/rooch/src/commands/init.rs +++ b/crates/rooch/src/commands/init.rs @@ -20,8 +20,8 @@ pub struct Init { } #[async_trait] -impl CommandAction<()> for Init { - async fn execute(self) -> RoochResult<()> { +impl CommandAction for Init { + async fn execute(self) -> RoochResult { let client_config_path = match self.context_options.config_dir { Some(v) => { if !v.exists() { @@ -31,7 +31,7 @@ impl CommandAction<()> for Init { } None => rooch_config_dir()?.join(ROOCH_CLIENT_CONFIG), }; - // Prompt user for connect to devnet fullnode if config does not exist. + // Prompt user for connect to devnet fullnode if config does not exist. if !client_config_path.exists() { let env = match std::env::var_os("ROOCH_CONFIG_WITH_RPC_URL") { Some(v) => Some(Env { @@ -112,8 +112,20 @@ impl CommandAction<()> for Init { .persisted(client_config_path.as_path()) .save()?; } + + let message = format!( + "Rooch config file generated at {}", + client_config_path.display() + ); + + return Ok(message); } - Ok(()) + let message = format!( + "Rooch config file already exists at {}", + client_config_path.display() + ); + + Ok(message) } } diff --git a/moveos/moveos-stdlib/move-stdlib/doc/error.md b/moveos/moveos-stdlib/move-stdlib/doc/error.md index eb2890523f..991ffee539 100644 --- a/moveos/moveos-stdlib/move-stdlib/doc/error.md +++ b/moveos/moveos-stdlib/move-stdlib/doc/error.md @@ -198,7 +198,7 @@ Construct a canonical error code from a category and a reason.
public fun canonical(category: u64, reason: u64): u64 {
-  (category << 16) + reason
+  (category * 10000) + reason
 }
 
diff --git a/moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move b/moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move index 3d988b44f3..347ea3e2b2 100644 --- a/moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move +++ b/moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move @@ -204,4 +204,154 @@ module moveos_std::account_storage { }); storage_context::drop_test_context(ctx); } + + #[test(sender=@0x42)] + fun test_move_to_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + global_move_to(&mut ctx, &sender, Test{ + addr: sender_addr, + version: 1, + }); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + fun test_move_from_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + global_move_to(&mut ctx, &sender, Test{ + addr: sender_addr, + version: 1, + }); + let Test { + addr, + version + } = global_move_from(&mut ctx, sender_addr); + assert!(addr == sender_addr, 0x10); + assert!(version == 1, 0x11); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + #[expected_failure(abort_code = 0x0, location = Self)] + fun test_failure_repeatedly_create_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + create_account_storage(&mut ctx, sender_addr); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + #[expected_failure(abort_code = 0x1, location = Self)] + fun test_failure_repeatedly_move_to_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + global_move_to(&mut ctx, &sender, Test{ + addr: sender_addr, + version: 1, + }); + global_move_to(&mut ctx, &sender, Test{ + addr: sender_addr, + version: 1, + }); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + #[expected_failure(abort_code = 0x2, location = Self)] + fun test_failure_repeatedly_move_from_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + global_move_to(&mut ctx, &sender, Test{ + addr: sender_addr, + version: 1, + }); + let Test { + addr: _, + version: _ + } = global_move_from(&mut ctx, sender_addr); + let Test { + addr: _, + version: _ + } = global_move_from(&mut ctx, sender_addr); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + fun test_global_borrow_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + global_move_to(&mut ctx, &sender, Test{ + addr: sender_addr, + version: 1, + }); + + let ref_test = global_borrow(& ctx, sender_addr); + assert!( ref_test.version == 1, 1); + assert!( ref_test.addr == sender_addr, 2); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + fun test_global_borrow_mut_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + global_move_to(&mut ctx, &sender, Test{ + addr: sender_addr, + version: 1, + }); + + let ref_test = global_borrow_mut(&mut ctx, sender_addr); + assert!( ref_test.version == 1, 1); + assert!( ref_test.addr == sender_addr, 2); + + ref_test.version = 2; + assert!( ref_test.version == 2, 3); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + #[expected_failure(abort_code = 0x6507, location = moveos_std::raw_table)] + fun test_failure_global_borrow_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + global_borrow(&mut ctx, sender_addr); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + #[expected_failure(abort_code = 0x6507, location = moveos_std::raw_table)] + fun test_failure_global_borrow_mut_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + create_account_storage(&mut ctx, sender_addr); + global_borrow_mut(&mut ctx, sender_addr); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + fun test_exist_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + assert!(exist_account_storage(&ctx , sender_addr) == false, 1); + storage_context::drop_test_context(ctx); + } + + #[test(sender=@0x42)] + fun test_ensure_account_storage(sender: signer){ + let sender_addr = signer::address_of(&sender); + let ctx = storage_context::new_test_context(sender_addr); + ensure_account_storage(&mut ctx , sender_addr); + assert!(exist_account_storage(&ctx , sender_addr), 1); + storage_context::drop_test_context(ctx); + } } \ No newline at end of file diff --git a/moveos/moveos-verifier/src/metadata.rs b/moveos/moveos-verifier/src/metadata.rs index 2b13272729..e8adc74040 100644 --- a/moveos/moveos-verifier/src/metadata.rs +++ b/moveos/moveos-verifier/src/metadata.rs @@ -224,7 +224,9 @@ impl<'a> ExtendedChecker<'a> { } } } + } + for ref fun in module.get_functions() { // Inspect the bytecode of every function, and if an instruction is CallGeneric, // verify that it calls a function with the private_generics attribute as detected earlier. // Then, ensure that the generic parameters of the CallGeneric instruction are valid. diff --git a/moveos/moveos/src/moveos_test_runner.rs b/moveos/moveos/src/moveos_test_runner.rs index 1f98da2b66..c1713716bf 100644 --- a/moveos/moveos/src/moveos_test_runner.rs +++ b/moveos/moveos/src/moveos_test_runner.rs @@ -230,6 +230,14 @@ fn merge_output(left: Option, right: Option) -> Option { } } +fn filter_temp_path(input: String) -> String { + let re = Regex::new("/tmp/.[0-9a-zA-Z]+").unwrap(); + let re1 = Regex::new("/var/.*tmp[0-9a-zA-Z]+").unwrap(); + let re_output = re.replace_all(input.as_str(), FIXED_TEMP_PATH).to_string(); + re1.replace_all(re_output.as_str(), FIXED_TEMP_PATH) + .to_string() +} + fn compile_source_unit( pre_compiled_deps: Option<&FullyCompiledProgram>, named_address_mapping: BTreeMap, @@ -253,16 +261,7 @@ fn compile_source_unit( if global_env.diag_count(Severity::Warning) > 0 { let mut buffer = Buffer::no_color(); global_env.report_diag(&mut buffer, Severity::Warning); - let warn_msg = String::from_utf8_lossy(buffer.as_slice()).to_string(); - let re = Regex::new("/tmp/.[0-9a-zA-Z]+").unwrap(); - let re1 = Regex::new("/var/.*tmp[0-9a-zA-Z]+").unwrap(); - let output = re - .replace_all(warn_msg.as_str(), FIXED_TEMP_PATH) - .to_string(); - Some( - re1.replace_all(output.as_str(), FIXED_TEMP_PATH) - .to_string(), - ) + Some(String::from_utf8_lossy(buffer.as_slice()).to_string()) } else { None } @@ -301,17 +300,25 @@ fn compile_source_unit( } } - Err(anyhow!(rendered_diags(&files, diags).unwrap())) + Err(anyhow!(filter_temp_path( + rendered_diags(&files, diags).unwrap() + ))) } Ok((mut units, warnings)) => { let warnings = rendered_diags(&files, warnings); + let merged_output = merge_output(extended_checks_error, warnings); + + let modified_merged_error = merged_output.map(filter_temp_path); + + if let Some(merged_error_message) = modified_merged_error { + return Err(anyhow::Error::msg(merged_error_message)); + } let len = units.len(); if len != 1 { panic!("Invalid input. Expected 1 compiled unit but got {}", len) } let unit = units.pop().unwrap(); - let merged_output = merge_output(extended_checks_error, warnings); - Ok((unit, merged_output)) + Ok((unit, modified_merged_error)) } } } diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100644 index 0000000000..90ba0329c8 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,10 @@ +#!/bin/bash +rm -rf rooch-artifacts/* +mkdir -p rooch-artifacts/ +cp -v target/release/rooch rooch-artifacts/ +cp -v README.md rooch-artifacts/ +if [ "$1" == "windows-latest" ]; then + 7z a -r rooch-$1.zip rooch-artifacts +else + zip -r rooch-$1.zip rooch-artifacts +fi