diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index cdfc9d6132..21ac373bca 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -92,5 +92,5 @@ jobs: chmod 600 private_key.pem sudo apt update sudo apt install -y --no-install-recommends openssh-server - ssh -o StrictHostKeyChecking=no -i private_key.pem $USER@$HOST bash -c "'sleep 30' && docker image prune -a -f && docker ps | grep main_debug | awk '{print \$1}' | xargs -r docker stop && docker ps -a | grep main_debug | awk '{print \$1}' | xargs -r docker rm -f && docker pull 'ghcr.io/rooch-network/rooch:main_debug' && docker run --rm -v /root:/root ghcr.io/rooch-network/rooch:main_debug server clean -n dev -f && docker run -d -v /root:/root -p 6767:6767 -p 9184:9184 'ghcr.io/rooch-network/rooch:main_debug' server start -n dev --btc-rpc-url '${{secrets.BTC_REGTEST_RPC_URL}}' --btc-rpc-username rooch-regtest --btc-rpc-password '${{secrets.BTC_REGTEST_RPC_PWD}}' --da '{\"internal-da-server\": {\"servers\": [{\"open-da\": {\"scheme\": \"fs\"}}]}}' --traffic-burst-size 100000 --traffic-per-second 10000" + ssh -o StrictHostKeyChecking=no -i private_key.pem $USER@$HOST bash -c "'sleep 30' && docker image prune -a -f && docker ps | grep main_debug | awk '{print \$1}' | xargs -r docker stop && docker ps -a | grep main_debug | awk '{print \$1}' | xargs -r docker rm -f && docker pull 'ghcr.io/rooch-network/rooch:main_debug' && docker run --rm -v /root:/root ghcr.io/rooch-network/rooch:main_debug server clean -n dev -f && docker run -d -v /root:/root -p 6767:6767 -p 9184:9184 'ghcr.io/rooch-network/rooch:main_debug' server start -n dev --btc-rpc-url '${{secrets.BTC_REGTEST_RPC_URL}}' --btc-rpc-username rooch-regtest --btc-rpc-password '${{secrets.BTC_REGTEST_RPC_PWD}}' --da '{\"da-backend\": {\"backends\": [{\"open-da\": {\"scheme\": \"fs\"}}]}}' --traffic-burst-size 100000 --traffic-per-second 1" ssh -o StrictHostKeyChecking=no -i private_key.pem $USER@$HOST "cd /root/rooch && git pull origin main && bash scripts/check_dev_deploy_status.sh main_debug '${{ secrets.TESTNET_MNEMONIC_PHRASE }}'" diff --git a/Cargo.lock b/Cargo.lock index 28746d8a7a..d383769dd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ dependencies = [ [[package]] name = "accumulator" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs-ext", @@ -415,7 +415,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint 0.4.5", "num-traits 0.2.19", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -498,7 +498,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -623,7 +623,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -634,7 +634,7 @@ version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -683,7 +683,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -730,13 +730,13 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", - "axum-core 0.4.4", - "base64 0.21.7", + "axum-core 0.4.5", + "base64 0.22.1", "bytes", "futures-util", "http 1.1.0", @@ -758,7 +758,7 @@ dependencies = [ "sha1", "sync_wrapper 1.0.1", "tokio", - "tokio-tungstenite 0.23.1", + "tokio-tungstenite 0.24.0", "tower 0.5.1", "tower-layer", "tower-service", @@ -784,9 +784,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -984,7 +984,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3deeecb812ca5300b7d3f66f730cc2ebd3511c3d36c691dd79c165d5b19a26e3" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -1010,7 +1010,7 @@ dependencies = [ "itertools 0.12.1", "lazy_static 1.5.0", "lazycell", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "regex", "rustc-hash 1.1.0", @@ -1100,10 +1100,10 @@ checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" [[package]] name = "bitcoin-move" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", - "axum 0.7.6", + "axum 0.7.7", "bitcoin 0.32.3", "brotli 3.5.0", "hex", @@ -1458,7 +1458,7 @@ version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -1848,7 +1848,7 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -1860,7 +1860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -2035,9 +2035,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5beedbbcf3526d3c8d195e43d9590066887651099c306a7cab75339ab56773" +checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" dependencies = [ "cfg-if", "cpufeatures", @@ -2067,7 +2067,7 @@ version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "unicode-xid 0.2.4", ] @@ -2169,7 +2169,7 @@ name = "cosmwasm-derive" version = "2.1.3" source = "git+https://github.com/rooch-network/cosmwasm?rev=597d3e8437d8c4d1afce07e5a676c29c751a8a81#597d3e8437d8c4d1afce07e5a676c29c751a8a81" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -2563,7 +2563,7 @@ dependencies = [ "cucumber-expressions", "inflections", "itertools 0.13.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "regex", "syn 2.0.65", @@ -2606,7 +2606,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -2662,7 +2662,7 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "strsim 0.10.0", "syn 1.0.109", @@ -2676,7 +2676,7 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "strsim 0.10.0", "syn 1.0.109", @@ -2690,7 +2690,7 @@ checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "strsim 0.11.1", "syn 2.0.65", @@ -2785,7 +2785,7 @@ dependencies = [ [[package]] name = "data-verify" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "rooch-rpc-api", @@ -2862,7 +2862,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -2873,7 +2873,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -2884,7 +2884,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -2914,7 +2914,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" dependencies = [ "darling 0.14.4", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -2926,7 +2926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" dependencies = [ "darling 0.20.9", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -2958,7 +2958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "rustc_version 0.4.0", "syn 2.0.65", @@ -2979,7 +2979,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", "unicode-xid 0.2.4", @@ -3013,7 +3013,7 @@ checksum = "59de76a222c2b8059f789cbe07afbfd8deb8c31dd0bc2a21f85e256c1def8259" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -3169,7 +3169,7 @@ dependencies = [ "darling 0.20.9", "either", "heck 0.5.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -3196,7 +3196,7 @@ dependencies = [ "byteorder", "lazy_static 1.5.0", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -3386,7 +3386,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -3398,7 +3398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -3409,7 +3409,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -3430,7 +3430,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ "darling 0.20.9", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -3604,7 +3604,7 @@ dependencies = [ "ethers-etherscan", "eyre", "prettyplease", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "regex", "reqwest 0.11.27", @@ -3625,7 +3625,7 @@ dependencies = [ "const-hex", "ethers-contract-abigen", "ethers-core", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "serde_json", "syn 2.0.65", @@ -3941,7 +3941,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c0c2af2157f416cb885e11d36cd0de2753f6d5384752d364075c835f5f8f891" dependencies = [ "convert_case 0.6.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -4038,7 +4038,7 @@ dependencies = [ "num-bigint 0.3.3", "num-integer", "num-traits 0.2.19", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -4178,7 +4178,7 @@ dependencies = [ [[package]] name = "framework-builder" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -4202,7 +4202,7 @@ dependencies = [ [[package]] name = "framework-release" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -4218,7 +4218,7 @@ dependencies = [ [[package]] name = "framework-types" -version = "0.7.2" +version = "0.7.3" dependencies = [ "move-core-types", "moveos-stdlib", @@ -4264,9 +4264,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -4279,9 +4279,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -4289,15 +4289,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -4306,9 +4306,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-locks" @@ -4322,26 +4322,26 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -4355,9 +4355,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -4423,7 +4423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -4491,7 +4491,7 @@ dependencies = [ "bstr", "log", "regex-automata", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", ] [[package]] @@ -5164,7 +5164,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -5188,7 +5188,7 @@ checksum = "0a0c890c85da4bab7bce4204c707396bbd3c6c8a681716a51c8814cfc2b682df" dependencies = [ "anyhow", "proc-macro-hack", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -5639,7 +5639,7 @@ checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" dependencies = [ "heck 0.4.1", "proc-macro-crate 1.3.1", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -5652,7 +5652,7 @@ checksum = "7895f186d5921065d96e16bd795e5ca89ac8356ec423fafc6e3d7cf8ec11aee4" dependencies = [ "heck 0.5.0", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -5837,7 +5837,7 @@ dependencies = [ "lalrpop-util", "petgraph 0.6.5", "regex", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", "string_cache", "term", "tiny-keccak", @@ -5871,7 +5871,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "regex", "syn 2.0.65", @@ -5942,7 +5942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -6158,11 +6158,11 @@ dependencies = [ [[package]] name = "metrics" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", - "axum 0.7.6", + "axum 0.7.7", "axum-server", "dashmap 6.0.1", "futures", @@ -6194,7 +6194,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd" dependencies = [ "migrations_internals", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", ] @@ -6951,7 +6951,7 @@ dependencies = [ [[package]] name = "moveos" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "backtrace", @@ -6993,7 +6993,7 @@ dependencies = [ [[package]] name = "moveos-common" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -7008,7 +7008,7 @@ dependencies = [ [[package]] name = "moveos-compiler" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "move-binary-format", @@ -7017,7 +7017,7 @@ dependencies = [ [[package]] name = "moveos-config" -version = "0.7.2" +version = "0.7.3" dependencies = [ "clap 4.5.17", "serde 1.0.210", @@ -7026,7 +7026,7 @@ dependencies = [ [[package]] name = "moveos-eventbus" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "coerce", @@ -7040,7 +7040,7 @@ dependencies = [ [[package]] name = "moveos-gas-profiling" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "handlebars", @@ -7057,7 +7057,7 @@ dependencies = [ [[package]] name = "moveos-object-runtime" -version = "0.7.2" +version = "0.7.3" dependencies = [ "better_any", "hex", @@ -7073,7 +7073,7 @@ dependencies = [ [[package]] name = "moveos-stdlib" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "base64 0.22.1", @@ -7108,7 +7108,7 @@ dependencies = [ [[package]] name = "moveos-store" -version = "0.7.2" +version = "0.7.3" dependencies = [ "accumulator", "anyhow", @@ -7130,7 +7130,7 @@ dependencies = [ [[package]] name = "moveos-types" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -7157,7 +7157,7 @@ dependencies = [ [[package]] name = "moveos-verifier" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -7183,7 +7183,7 @@ dependencies = [ [[package]] name = "moveos-wasm" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "once_cell", @@ -7452,7 +7452,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -7543,7 +7543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -7568,12 +7568,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" -dependencies = [ - "portable-atomic", -] +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" @@ -7607,7 +7604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" dependencies = [ "bytes", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -7662,7 +7659,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -7737,7 +7734,7 @@ checksum = "03f2cb802b5bdfdf52f1ffa0b54ce105e4d346e91990dd571f86c91321ad49e2" dependencies = [ "Inflector", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -7804,7 +7801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -7816,7 +7813,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -7969,7 +7966,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "636d60acf97633e48d266d7415a9355d4389cea327a193f87df395d88cd2b14d" dependencies = [ "peg-runtime", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", ] @@ -8051,7 +8048,7 @@ checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -8135,7 +8132,7 @@ checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared 0.11.2", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -8160,20 +8157,20 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -8396,7 +8393,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "syn 2.0.65", ] @@ -8461,7 +8458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", "version_check", @@ -8473,7 +8470,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "version_check", ] @@ -8495,9 +8492,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -8531,7 +8528,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -8597,7 +8594,7 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -8610,7 +8607,7 @@ checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -8667,7 +8664,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -8800,7 +8797,7 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", ] [[package]] @@ -8926,7 +8923,7 @@ dependencies = [ [[package]] name = "raw-store" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "metrics", @@ -8969,7 +8966,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a25d631e41bfb5fdcde1d4e2215f62f7f0afa3ff11e26563765bd6ea1d229aeb" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -9027,7 +9024,7 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -9046,25 +9043,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", ] [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", ] [[package]] @@ -9075,9 +9072,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "region" @@ -9358,7 +9355,7 @@ version = "0.7.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -9380,7 +9377,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -9396,7 +9393,7 @@ dependencies = [ [[package]] name = "rooch" -version = "0.7.2" +version = "0.7.3" dependencies = [ "accumulator", "anyhow", @@ -9496,7 +9493,7 @@ dependencies = [ [[package]] name = "rooch-benchmarks" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -9551,20 +9548,23 @@ dependencies = [ [[package]] name = "rooch-common" -version = "0.7.2" +version = "0.7.3" dependencies = [ "libc", ] [[package]] name = "rooch-config" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", + "celestia-types", "clap 4.5.17", "dirs", "dirs-next", + "hex", "moveos-config", + "moveos-types", "once_cell", "rooch-types", "serde 1.0.210", @@ -9574,7 +9574,7 @@ dependencies = [ [[package]] name = "rooch-cosmwasm-vm" -version = "0.7.2" +version = "0.7.3" dependencies = [ "accumulator", "anyhow", @@ -9596,7 +9596,7 @@ dependencies = [ [[package]] name = "rooch-da" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", @@ -9604,20 +9604,20 @@ dependencies = [ "celestia-rpc", "celestia-types", "coerce", - "futures", "log", - "lz4", "moveos-types", "opendal", "rooch-config", + "rooch-store", + "rooch-types", "serde 1.0.210", "serde_yaml 0.9.34+deprecated", - "xxhash-rust", + "tokio", ] [[package]] name = "rooch-db" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "moveos-store", @@ -9632,7 +9632,7 @@ dependencies = [ [[package]] name = "rooch-event" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", @@ -9644,13 +9644,12 @@ dependencies = [ [[package]] name = "rooch-executor" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", "coerce", "function_name", - "hex", "log", "metrics", "move-core-types", @@ -9671,11 +9670,11 @@ dependencies = [ [[package]] name = "rooch-faucet" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", - "axum 0.7.6", + "axum 0.7.7", "axum-server", "bcs", "clap 4.5.17", @@ -9700,7 +9699,7 @@ dependencies = [ [[package]] name = "rooch-framework" -version = "0.7.2" +version = "0.7.3" dependencies = [ "bcs", "bitcoin 0.32.3", @@ -9721,7 +9720,7 @@ dependencies = [ [[package]] name = "rooch-framework-tests" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -9761,7 +9760,7 @@ dependencies = [ [[package]] name = "rooch-genesis" -version = "0.7.2" +version = "0.7.3" dependencies = [ "accumulator", "anyhow", @@ -9792,7 +9791,7 @@ dependencies = [ [[package]] name = "rooch-indexer" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", @@ -9822,7 +9821,7 @@ dependencies = [ [[package]] name = "rooch-integration-test-runner" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -9855,7 +9854,7 @@ dependencies = [ [[package]] name = "rooch-key" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "argon2", @@ -9874,7 +9873,7 @@ dependencies = [ [[package]] name = "rooch-nursery" -version = "0.7.2" +version = "0.7.3" dependencies = [ "bcs", "bitcoin 0.32.3", @@ -9907,7 +9906,7 @@ dependencies = [ [[package]] name = "rooch-open-rpc" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "clap 4.5.17", @@ -9922,11 +9921,11 @@ dependencies = [ [[package]] name = "rooch-open-rpc-macros" -version = "0.7.2" +version = "0.7.3" dependencies = [ "derive-syn-parse", "itertools 0.13.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", "unescape", @@ -9934,7 +9933,7 @@ dependencies = [ [[package]] name = "rooch-open-rpc-spec" -version = "0.7.2" +version = "0.7.3" dependencies = [ "clap 4.5.17", "pretty_assertions", @@ -9946,7 +9945,7 @@ dependencies = [ [[package]] name = "rooch-open-rpc-spec-builder" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "clap 4.5.17", @@ -9979,7 +9978,7 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tokio-tungstenite 0.23.1", + "tokio-tungstenite 0.24.0", "tracing", "tracing-subscriber", "tungstenite 0.24.0", @@ -9987,7 +9986,7 @@ dependencies = [ [[package]] name = "rooch-ord" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", @@ -10013,7 +10012,7 @@ dependencies = [ [[package]] name = "rooch-pipeline-processor" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", @@ -10041,7 +10040,7 @@ dependencies = [ [[package]] name = "rooch-proposer" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", @@ -10057,7 +10056,7 @@ dependencies = [ [[package]] name = "rooch-relayer" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "async-trait", @@ -10086,7 +10085,7 @@ dependencies = [ [[package]] name = "rooch-rpc-api" -version = "0.7.2" +version = "0.7.3" dependencies = [ "accumulator", "anyhow", @@ -10111,7 +10110,7 @@ dependencies = [ [[package]] name = "rooch-rpc-client" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -10135,10 +10134,10 @@ dependencies = [ [[package]] name = "rooch-rpc-server" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", - "axum 0.7.6", + "axum 0.7.7", "bcs", "bitcoincore-rpc", "coerce", @@ -10185,7 +10184,7 @@ dependencies = [ [[package]] name = "rooch-sequencer" -version = "0.7.2" +version = "0.7.3" dependencies = [ "accumulator", "anyhow", @@ -10210,10 +10209,11 @@ dependencies = [ [[package]] name = "rooch-store" -version = "0.7.2" +version = "0.7.3" dependencies = [ "accumulator", "anyhow", + "moveos-common", "moveos-config", "moveos-types", "once_cell", @@ -10225,7 +10225,7 @@ dependencies = [ [[package]] name = "rooch-test-transaction-builder" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "bcs", @@ -10239,7 +10239,7 @@ dependencies = [ [[package]] name = "rooch-types" -version = "0.7.2" +version = "0.7.3" dependencies = [ "accumulator", "anyhow", @@ -10259,6 +10259,7 @@ dependencies = [ "framework-builder", "framework-types", "hex", + "lz4", "move-binary-format", "move-command-line-common", "move-core-types", @@ -10279,6 +10280,7 @@ dependencies = [ "strum_macros", "thiserror", "tracing", + "xxhash-rust", ] [[package]] @@ -10641,7 +10643,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -10684,7 +10686,7 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "serde_derive_internals", "syn 2.0.65", @@ -10742,7 +10744,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -10996,7 +10998,7 @@ version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -11007,7 +11009,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -11041,7 +11043,7 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -11118,7 +11120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ "darling 0.13.4", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -11130,7 +11132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ "darling 0.20.9", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -11142,7 +11144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling 0.20.9", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -11440,7 +11442,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -11453,7 +11455,7 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smt" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "backtrace", @@ -11635,7 +11637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "rustversion", "syn 2.0.65", @@ -11735,7 +11737,7 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "unicode-ident", ] @@ -11746,7 +11748,7 @@ version = "2.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "unicode-ident", ] @@ -11793,7 +11795,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78bfa6ec52465e2425fd43ce5bbbe0f0b623964f7c63feb6b10980e816c654ea" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "sealed", "syn 2.0.65", @@ -11998,7 +12000,7 @@ dependencies = [ [[package]] name = "testsuite" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "assert_cmd", @@ -12050,7 +12052,7 @@ version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -12109,7 +12111,7 @@ dependencies = [ [[package]] name = "timeout-join-handler" -version = "0.7.2" +version = "0.7.3" dependencies = [ "anyhow", "thiserror", @@ -12126,14 +12128,13 @@ dependencies = [ [[package]] name = "tiny-bip39" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" +checksum = "4a6e875ccbd782b2d91350816d4ab27da3c9424c381f9ba07ed3e2e1ae680d90" dependencies = [ "anyhow", - "hmac", "once_cell", - "pbkdf2 0.11.0", + "pbkdf2 0.12.2", "rand 0.8.5", "rustc-hash 1.1.0", "sha2 0.10.8", @@ -12211,7 +12212,7 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -12303,16 +12304,16 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", "native-tls", "tokio", "tokio-native-tls", - "tungstenite 0.23.0", + "tungstenite 0.24.0", ] [[package]] @@ -12545,7 +12546,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "313fa625fea5790ed56360a30ea980e41229cf482b4835801a67ef1922bf63b9" dependencies = [ - "axum 0.7.6", + "axum 0.7.7", "forwarded-header-value", "governor", "http 1.1.0", @@ -12561,7 +12562,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ad0c048e114d19d1140662762bfdb10682f3bc806d8be18af846600214dd9af" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -12584,7 +12585,7 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -12640,7 +12641,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -12705,25 +12706,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "tungstenite" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "native-tls", - "rand 0.8.5", - "sha1", - "thiserror", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.24.0" @@ -12736,6 +12718,7 @@ dependencies = [ "http 1.1.0", "httparse", "log", + "native-tls", "rand 0.8.5", "sha1", "thiserror", @@ -12763,7 +12746,7 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29a3151c41d0b13e3d011f98adc24434560ef06673a155a6c7f66b9879eecce2" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -13013,7 +12996,7 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee1cd046f83ea2c4e920d6ee9f7c3537ef928d75dce5d84a87c2c5d6b3999a3a" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -13033,7 +13016,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d44690c645190cfce32f91a1582281654b2338c6073fa250b0949fd25c55b32" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -13191,7 +13174,7 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", "wasm-bindgen-shared", @@ -13225,7 +13208,7 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", "wasm-bindgen-backend", @@ -13386,7 +13369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45ab99baa393da623dbca6390c17bd9cd7666e8c48f6b42b4f8c635106a09ca8" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -13940,7 +13923,7 @@ version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] @@ -13960,7 +13943,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.65", ] diff --git a/Cargo.toml b/Cargo.toml index 773cca1484..05bfb4d01b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ license = "Apache-2.0" publish = false repository = "https://github.com/rooch-network/rooch" rust-version = "1.78.0" -version = "0.7.2" +version = "0.7.3" [workspace.dependencies] # Internal crate dependencies. @@ -180,8 +180,8 @@ ethereum-types = "0.14.1" ethers = { version = "2.0.7", features = ["legacy"] } eyre = "0.6.8" fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "56f6223b84ada922b6cb2c672c69db2ea3dc6a13" } -futures = "0.3.28" -futures-util = "0.3.30" +futures = "0.3.31" +futures-util = "0.3.31" hex = "0.4.3" rustc-hex = "2.1" itertools = "0.13.0" @@ -193,7 +193,7 @@ log = "0.4.22" more-asserts = "0.3.0" num-derive = "0.3.3" num-traits = "0.2.15" -once_cell = "1.20.1" +once_cell = "1.20.2" ordinals = "0.0.9" parking_lot = "0.12.3" pathdiff = "0.2.1" @@ -224,10 +224,10 @@ sha3 = "0.10.8" smallvec = "1.6.1" thiserror = "1.0.64" tiny-keccak = { version = "2", features = ["keccak", "sha3"] } -tiny-bip39 = "1.0.0" +tiny-bip39 = "1.0.1" tokio = { version = "1.40.0", features = ["full"] } tokio-util = "0.7.12" -tokio-tungstenite = { version = "0.23.1", features = ["native-tls"] } +tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] } tokio-stream = "0.1.16" tonic = { version = "0.8", features = ["gzip"] } tracing = "0.1.37" @@ -242,11 +242,11 @@ versions = "4.1.0" pretty_assertions = "1.4.1" syn = { version = "1.0.104", features = ["full", "extra-traits"] } quote = "1.0" -proc-macro2 = "1.0.86" +proc-macro2 = "1.0.87" derive-syn-parse = "0.1.5" unescape = "0.1.0" tempfile = "3.12.0" -regex = "1.10.6" +regex = "1.11.0" walkdir = "2.3.3" prometheus = "0.13.3" prometheus-http-query = { version = "0.6.6", default_features = false, features = [ @@ -265,7 +265,7 @@ http = "1.0.0" tower = { version = "0.5.1", features = ["full", "util", "timeout", "load-shed", "limit"] } tower-http = { version = "0.5.2", features = ["cors", "full", "trace", "set-header", "propagate-header"] } tower_governor = "0.4.2" -pin-project = "1.0.12" +pin-project = "1.1.6" mirai-annotations = "1.12.0" lru = "0.11.0" bs58 = "0.5.1" @@ -278,7 +278,7 @@ rpassword = "7.2.0" fixed-hash = "0.8.0" uint = "0.9.5" rlp = "0.5.2" -const-hex = "1.13.0" +const-hex = "1.13.1" cached = "0.43.0" diesel = { version = "2.2.4", features = [ "chrono", @@ -289,7 +289,7 @@ diesel = { version = "2.2.4", features = [ ] } diesel-derive-enum = { version = "2.1.0", features = ["sqlite"] } diesel_migrations = { version = "2.2.0" } -axum = { version = "0.7.6", default-features = false, features = [ +axum = { version = "0.7.7", default-features = false, features = [ "tokio", "http1", "http2", diff --git a/crates/rooch-config/Cargo.toml b/crates/rooch-config/Cargo.toml index dd9cb0ded1..d432b3297e 100644 --- a/crates/rooch-config/Cargo.toml +++ b/crates/rooch-config/Cargo.toml @@ -22,6 +22,9 @@ dirs = { workspace = true } once_cell = { workspace = true } clap = { workspace = true } dirs-next = { workspace = true } +celestia-types = { workspace = true } +hex = { workspace = true } rooch-types = { workspace = true } moveos-config = { workspace = true } +moveos-types = { workspace = true } diff --git a/crates/rooch-config/src/config.rs b/crates/rooch-config/src/config.rs index db639c1311..24d31d38c9 100644 --- a/crates/rooch-config/src/config.rs +++ b/crates/rooch-config/src/config.rs @@ -4,17 +4,9 @@ use anyhow::Context; use serde::de::DeserializeOwned; use serde::Serialize; -use std::collections::HashMap; -use std::error::Error; use std::fs; use std::path::{Path, PathBuf}; -pub enum MapConfigValueSource { - ConfigKey, // Value came from the presence of a key in the configuration - Environment, // Value came from the environment - Default, // Value came from a defined default value -} - pub trait Config where Self: DeserializeOwned + Serialize, @@ -82,113 +74,3 @@ impl std::ops::DerefMut for PersistedConfig { &mut self.inner } } - -pub fn parse_hashmap( - s: &str, -) -> Result, Box> { - s.split(',') - .filter(|kv| !kv.is_empty()) - .map(|kv| { - let mut parts = kv.splitn(2, '='); - match (parts.next(), parts.next()) { - (Some(key), Some(value)) if !key.trim().is_empty() => { - Ok((key.to_string(), value.to_string())) - } - (Some(""), Some(_)) => Err("key is missing before '='".into()), - _ => { - Err("each key=value pair must be separated by a comma and contain a key".into()) - } - } - }) - .collect() -} - -// value order: -// 1. key value -// 2. env value -// 3. default value -pub fn retrieve_map_config_value( - config: &mut HashMap, - key: &str, - env_var: Option<&str>, - default_var: &str, -) -> MapConfigValueSource { - if config.contains_key(key) { - return MapConfigValueSource::ConfigKey; - } - - if let Some(env_var) = env_var { - if let Ok(env_var_value) = std::env::var(env_var) { - // env_var exists - config.insert(key.to_string(), env_var_value.clone()); - return MapConfigValueSource::Environment; - } - } - - // Use the default - config.insert(key.to_string(), default_var.to_string()); - MapConfigValueSource::Default -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_hashmap_ok() { - let input = "key1=VALUE1,key2=value2"; - let output = parse_hashmap(input).unwrap(); - - let mut expected = HashMap::new(); - expected.insert("key1".to_string(), "VALUE1".to_string()); - expected.insert("key2".to_string(), "value2".to_string()); - - assert_eq!(output, expected); - } - - #[test] - fn test_parse_hashmap_empty_value() { - let input = "key1=,key2=value2"; - let output = parse_hashmap(input).unwrap(); - - let mut expected = HashMap::new(); - expected.insert("key1".to_string(), "".to_string()); - expected.insert("key2".to_string(), "value2".to_string()); - - assert_eq!(output, expected); - } - - #[test] - fn test_parse_hashmap_empty_string() { - let input = ""; - let output = parse_hashmap(input).unwrap(); - - let expected = HashMap::new(); - - assert_eq!(output, expected); - } - - #[test] - fn test_parse_hashmap_missing_value() { - let input = "key1,key2=value2"; - let output = parse_hashmap(input); - - assert!(output.is_err()); - } - - #[test] - fn test_parse_hashmap_missing_key() { - let input = "=value1,key2=value2"; - let output = parse_hashmap(input); - - assert!(output.is_err()); - } - - #[test] - fn test_parse_hashmap_no_equals_sign() { - let input = "key1value1,key2=value2"; - let output = parse_hashmap(input); - - assert!(output.is_err()); - } -} diff --git a/crates/rooch-config/src/da_config.rs b/crates/rooch-config/src/da_config.rs index bc6fbc36a4..29abc1dd36 100644 --- a/crates/rooch-config/src/da_config.rs +++ b/crates/rooch-config/src/da_config.rs @@ -2,19 +2,19 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::Config; -use crate::config::{parse_hashmap, retrieve_map_config_value, MapConfigValueSource}; -use crate::BaseConfig; -use clap::Parser; +use crate::{retrieve_map_config_value, BaseConfig, MapConfigValueSource}; +use celestia_types::nmt::Namespace; +use hex::encode; +use moveos_types::h256::sha2_256_of; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; -use serde_json::Value; use std::collections::HashMap; use std::fmt::Display; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Arc; -static R_DEFAULT_OPENDA_FS_DIR: Lazy = Lazy::new(|| PathBuf::from("openda_fs")); +static R_DEFAULT_OPENDA_FS_DIR: Lazy = Lazy::new(|| PathBuf::from("openda-fs")); #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "lowercase")] @@ -26,20 +26,46 @@ pub enum DAServerSubmitStrategy { Number(usize), } +impl FromStr for DAServerSubmitStrategy { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "all" => Ok(DAServerSubmitStrategy::All), + "quorum" => Ok(DAServerSubmitStrategy::Quorum), + _ => { + if let Ok(n) = s.parse::() { + Ok(DAServerSubmitStrategy::Number(n)) + } else { + Err(format!("invalid da server submit strategy: {}", s)) + } + } + } + } +} + +impl Display for DAServerSubmitStrategy { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DAServerSubmitStrategy::All => write!(f, "all"), + DAServerSubmitStrategy::Quorum => write!(f, "quorum"), + DAServerSubmitStrategy::Number(n) => write!(f, "{}", n), + } + } +} + #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "lowercase")] pub enum OpenDAScheme { - // local filesystem, for developing only, config: - // root: file path to the root directory + // local filesystem, main config: + // root: file path #[default] Fs, - // gcs(Google Could Service) main config: + // gcs(Google Could Service), main config: // bucket - // root - // credential (it's okay to pass credential file path here, it'll be handled it automatically) + // credential/credential_path (using path instead) Gcs, - // s3 config: - // root + // s3, main config: // bucket // region // endpoint @@ -48,24 +74,37 @@ pub enum OpenDAScheme { S3, } -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "kebab-case")] -pub enum InternalDAServerConfigType { - Celestia(DAServerCelestiaConfig), - OpenDa(DAServerOpenDAConfig), +impl Display for OpenDAScheme { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + OpenDAScheme::Fs => write!(f, "fs"), + OpenDAScheme::Gcs => write!(f, "gcs"), + OpenDAScheme::S3 => write!(f, "s3"), + } + } +} + +impl FromStr for OpenDAScheme { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "gcs" => Ok(OpenDAScheme::Gcs), + "s3" => Ok(OpenDAScheme::S3), + "fs" => Ok(OpenDAScheme::Fs), + _ => Err("open-da scheme no match"), + } + } } -#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, Parser)] +#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize)] #[serde(deny_unknown_fields)] #[serde(rename_all = "kebab-case")] pub struct DAConfig { #[serde(skip_serializing_if = "Option::is_none")] - #[clap(name = "internal-da-server", long, help = "internal da server config")] - pub internal_da_server: Option, + pub da_backend: Option, #[serde(skip)] - #[clap(skip)] base: Option>, - // TODO external da server config } impl Display for DAConfig { @@ -96,20 +135,37 @@ impl DAConfig { let default_fs_root = self.get_openda_fs_dir(); - if let Some(InternalDAServerConfig { servers, .. }) = &mut self.internal_da_server { - for server in servers { - if let InternalDAServerConfigType::OpenDa(open_da_config) = server { + if let Some(backend_config) = &mut self.da_backend { + backend_config.adjust_submit_strategy(); + let backends = &mut backend_config.backends; + + for backend in backends { + if let DABackendConfigType::OpenDa(open_da_config) = backend { if matches!(open_da_config.scheme, OpenDAScheme::Fs) { - let var_source = retrieve_map_config_value( - &mut open_da_config.config, - "root", - None, - default_fs_root.to_str().unwrap(), - ); - if let MapConfigValueSource::Default = var_source { - if !default_fs_root.exists() { - std::fs::create_dir_all(default_fs_root.clone())?; + if let Some(fs_str) = default_fs_root.to_str() { + let var_source = retrieve_map_config_value( + &mut open_da_config.config, + "root", + None, + Some(fs_str), + ); + if let MapConfigValueSource::Default = var_source { + if !default_fs_root.exists() { + std::fs::create_dir_all(default_fs_root.clone()).map_err( + |e| { + anyhow::anyhow!( + "Failed to create OpenDA fs dir: {:?}", + e + ) + }, + )?; + } } + } else { + return Err(anyhow::anyhow!( + "Invalid UTF-8 path: {:?}", + default_fs_root + )); } } } @@ -132,43 +188,20 @@ impl DAConfig { } } -#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, Parser)] +#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] #[serde(deny_unknown_fields)] -pub struct InternalDAServerConfig { +pub struct DABackendConfig { #[serde(skip_serializing_if = "Option::is_none")] - #[clap( - name = "submit-strategy", - long, - help = "specifies the submission strategy of internal DA servers to be used. 'all' with all servers, 'quorum' with quorum servers, 'n' with n servers, etc." - )] - pub submit_strategy: Option, - #[clap( - name = "servers", - long, - help = "specifies the type of internal DA servers to be used. 'celestia' with corresponding Celestia server configuration, 'xxx' with corresponding xxx server configuration, etc." - )] - pub servers: Vec, + pub submit_strategy: Option, // specifies the submission strategy of DA. 'all' with all backends, 'quorum' with quorum backends, 'n' with n backends, etc. + pub backends: Vec, // specifies the type of DA backends to be used. 'celestia' with corresponding Celestia backend configuration, 'foo' with corresponding foo backend configuration, etc. } -impl InternalDAServerConfig { - pub fn adjust_submit_strategy(&mut self) { - let servers_count = self.servers.len(); - - // Set default strategy to All if it's None. - let strategy = self - .submit_strategy - .get_or_insert(DAServerSubmitStrategy::All); - - // If it's a Number, adjust the value to be within [1, n]. - if let DAServerSubmitStrategy::Number(ref mut num) = strategy { - *num = std::cmp::max(1, std::cmp::min(*num, servers_count)); - } - } - +impl DABackendConfig { pub fn calculate_submit_threshold(&mut self) -> usize { self.adjust_submit_strategy(); // Make sure submit_strategy is adjusted before calling this function. - let servers_count = self.servers.len(); + let servers_count = self.backends.len(); match self.submit_strategy { Some(DAServerSubmitStrategy::All) => servers_count, Some(DAServerSubmitStrategy::Quorum) => servers_count / 2 + 1, @@ -176,282 +209,119 @@ impl InternalDAServerConfig { None => servers_count, // Default to 'All' if submit_strategy is None } } -} - -impl FromStr for InternalDAServerConfig { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result { - let deserialized = serde_json::from_str(s)?; - Ok(deserialized) - } -} + fn adjust_submit_strategy(&mut self) { + let servers_count = self.backends.len(); -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Parser)] -#[serde(deny_unknown_fields)] -pub struct DAServerCelestiaConfig { - #[serde(skip_serializing_if = "Option::is_none")] - #[clap(name = "namespace", long, help = "celestia namespace")] - pub namespace: Option, - #[serde(skip_serializing_if = "Option::is_none")] - #[clap(name = "conn", long, help = "celestia node connection")] - pub conn: Option, - #[serde(skip_serializing_if = "Option::is_none")] - #[clap(name = "auth-token", long, help = "celestia node auth token")] - pub auth_token: Option, - // for celestia: - // support for up to 8 MB blocks, starting with 2MB at genesis and upgradeable through onchain governance. - #[serde(skip_serializing_if = "Option::is_none")] - #[clap( - name = "max-segment-size", - long, - help = "max segment size, striking a balance between throughput and the constraints on blob size." - )] - pub max_segment_size: Option, -} + // Set default strategy to All if it's None. + let strategy = self + .submit_strategy + .get_or_insert(DAServerSubmitStrategy::All); -impl Default for DAServerCelestiaConfig { - fn default() -> Self { - Self { - namespace: None, - conn: None, - auth_token: None, - max_segment_size: Some(1024 * 1024), + // If it's a Number, adjust the value to be within [1, n]. + if let DAServerSubmitStrategy::Number(ref mut num) = strategy { + *num = std::cmp::max(1, std::cmp::min(*num, servers_count)); } } } -impl DAServerCelestiaConfig { - pub fn new_with_defaults(mut self) -> Self { - let default = DAServerCelestiaConfig::default(); - if self.max_segment_size.is_none() { - self.max_segment_size = default.max_segment_size; - } - self - } +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum DABackendConfigType { + Celestia(DABackendCelestiaConfig), + OpenDa(DABackendOpenDAConfig), } -impl FromStr for InternalDAServerConfigType { - type Err = String; - - fn from_str(s: &str) -> Result { - let v: Value = - serde_json::from_str(s).map_err(|e| format!("Error parsing JSON: {}, {}", e, s))?; - - if let Some(obj) = v.as_object() { - if let Some(celestia) = obj.get("celestia") { - let celestia_config: DAServerCelestiaConfig = - serde_json::from_value(celestia.clone()).map_err(|e| { - format!( - "invalid celestia config: {} error: {}, original: {}", - celestia, e, s - ) - })?; - Ok(InternalDAServerConfigType::Celestia(celestia_config)) - } else if let Some(openda) = obj.get("open-da") { - let openda_config: DAServerOpenDAConfig = serde_json::from_value(openda.clone()) - .map_err(|e| { - format!( - "invalid open-da config: {}, error: {}, original: {}", - openda, e, s - ) - })?; - Ok(InternalDAServerConfigType::OpenDa(openda_config)) - } else { - Err(format!("Invalid value: {}", s)) - } - } else { - Err(format!("Invalid value: {}", s)) - } - } +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +#[serde(deny_unknown_fields)] +/// Celestia provides ability to access Celestia node +pub struct DABackendCelestiaConfig { + /// celestia namespace + pub namespace: Namespace, + /// celestia node connection + pub conn: String, + /// celestia node auth token + pub auth_token: String, + #[serde(skip_serializing_if = "Option::is_none")] + /// max segment size, striking a balance between throughput and the constraints on blob size in celestia network. + /// Set at crates/rooch-da/src/backend/celestia if None. + pub max_segment_size: Option, } -// Open DA provides ability to access various storage services -#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, Parser)] +#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] #[serde(deny_unknown_fields)] -pub struct DAServerOpenDAConfig { - #[clap( - name = "scheme", - long, - value_enum, - default_value = "fs", - help = "specifies the type of storage service to be used. 'gcs' with corresponding GCS server configuration, 's3' with corresponding S3 server configuration, etc." - )] +/// Open DA provides ability to access various storage services +pub struct DABackendOpenDAConfig { + /// specifies the type of storage service to be used. 'gcs' with corresponding GCS server configuration, 's3' with corresponding S3 server configuration, etc #[serde(default)] pub scheme: OpenDAScheme, - #[clap( - name = "config", - long, - value_parser = parse_hashmap, - help = "specifies the configuration of the storage service. 'gcs' with corresponding GCS server configuration, 's3' with corresponding S3 server configuration, etc." - )] - #[serde(default)] + /// specifies the configuration of the storage service. 'gcs' with corresponding GCS server configuration, 's3' with corresponding S3 server configuration, etc. pub config: HashMap, - #[serde(skip_serializing_if = "Option::is_none")] - #[clap( - name = "max-segment-size", - long, - help = "max segment size, striking a balance between throughput and the constraints on blob size." - )] + /// / is the path to store the segment. + /// If not set, the / is the full path + /// If root is set in config, the // is the full path + pub namespace: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// max segment size. + /// Set at crates/rooch-da/src/backend/openda if None. pub max_segment_size: Option, } -impl FromStr for DAServerSubmitStrategy { - type Err = String; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "all" => Ok(DAServerSubmitStrategy::All), - "quorum" => Ok(DAServerSubmitStrategy::Quorum), - _ => { - if let Ok(n) = s.parse::() { - Ok(DAServerSubmitStrategy::Number(n)) - } else { - Err(format!("invalid da server submit strategy: {}", s)) - } - } - } - } -} - -impl Display for OpenDAScheme { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - OpenDAScheme::Fs => write!(f, "fs"), - OpenDAScheme::Gcs => write!(f, "gcs"), - OpenDAScheme::S3 => write!(f, "s3"), - } - } -} - -impl FromStr for OpenDAScheme { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "gcs" => Ok(OpenDAScheme::Gcs), - "s3" => Ok(OpenDAScheme::S3), - "fs" => Ok(OpenDAScheme::Fs), - _ => Err("open-da scheme no match"), - } - } +/// Derive a namespace from genesis config for DA backend (as default namespace open-da backend) +/// first 7 chars of sha256 of genesis in hex is used as namespace +pub fn derive_genesis_namespace(genesis: &[u8]) -> String { + let raw = encode(sha2_256_of(genesis).0); + raw.chars().take(7).collect() } #[cfg(test)] mod tests { use super::*; + use celestia_types::nmt::Namespace; #[test] - fn test_adjust_submit_strategy_default_to_all() { - let mut config = InternalDAServerConfig { - submit_strategy: None, - servers: vec![], // Empty for this test + fn da_config_from_str() { + let da_config_str = r#"{"da-backend": {"submit-strategy": "all", + "backends": [{"celestia": {"namespace": "//////////////////////////////////////8=", "conn": "test-conn", "auth-token": "test-token", "max-segment-size": 2048}}, + {"open-da": {"scheme": "gcs", "config": {"bucket": "test-bucket", "credential": "test-credential"}}}]}}"#; + let exp_celestia_config = DABackendCelestiaConfig { + namespace: Namespace::PARITY_SHARE, + conn: "test-conn".to_string(), + auth_token: "test-token".to_string(), + max_segment_size: Some(2048), }; - config.adjust_submit_strategy(); - assert_eq!(config.submit_strategy, Some(DAServerSubmitStrategy::All)); - } - - #[test] - fn test_adjust_submit_strategy_number_too_low() { - let mut config = InternalDAServerConfig { - submit_strategy: Some(DAServerSubmitStrategy::Number(0)), - servers: vec![ - InternalDAServerConfigType::Celestia(DAServerCelestiaConfig::default()); - 2 - ], // Two servers for this test - }; - config.adjust_submit_strategy(); - assert_eq!( - config.submit_strategy, - Some(DAServerSubmitStrategy::Number(1)) - ); - } - - #[test] - fn test_adjust_submit_strategy_number_too_high() { - let mut config = InternalDAServerConfig { - submit_strategy: Some(DAServerSubmitStrategy::Number(5)), - servers: vec![ - InternalDAServerConfigType::Celestia(DAServerCelestiaConfig::default()); - 3 - ], // Three servers for this test + let exp_openda_config = DABackendOpenDAConfig { + scheme: OpenDAScheme::Gcs, + config: vec![ + ("bucket".to_string(), "test-bucket".to_string()), + ("credential".to_string(), "test-credential".to_string()), + ] + .into_iter() + .collect(), + namespace: None, + max_segment_size: None, }; - config.adjust_submit_strategy(); - assert_eq!( - config.submit_strategy, - Some(DAServerSubmitStrategy::Number(3)) - ); - } - - #[test] - fn test_adjust_submit_strategy_number_within_range() { - let mut config = InternalDAServerConfig { - submit_strategy: Some(DAServerSubmitStrategy::Number(2)), - servers: vec![ - InternalDAServerConfigType::Celestia(DAServerCelestiaConfig::default()); - 4 - ], // Four servers for this test + let exp_da_config = DAConfig { + da_backend: Some(DABackendConfig { + submit_strategy: Some(DAServerSubmitStrategy::All), + backends: vec![ + DABackendConfigType::Celestia(exp_celestia_config.clone()), + DABackendConfigType::OpenDa(exp_openda_config.clone()), + ], + }), + base: None, }; - config.adjust_submit_strategy(); - assert_eq!( - config.submit_strategy, - Some(DAServerSubmitStrategy::Number(2)) - ); - } - - #[test] - fn test_internal_da_server_config_str() { - let celestia_config_str = r#"{"celestia": {"namespace": "test_namespace", "conn": "test_conn", "auth_token": "test_token", "max_segment_size": 2048}}"#; - let openda_config_str = r#"{"open-da": {"scheme": "gcs", "config": {"Param1": "value1", "param2": "Value2"}, "max_segment_size": 2048}}"#; - let invalid_config_str = r#"{"unknown": {...}}"#; - - match InternalDAServerConfigType::from_str(celestia_config_str) { - Ok(InternalDAServerConfigType::Celestia(celestia_config)) => { - assert_eq!( - celestia_config, - DAServerCelestiaConfig { - namespace: Some("test_namespace".to_string()), - conn: Some("test_conn".to_string()), - auth_token: Some("test_token".to_string()), - max_segment_size: Some(2048), - } - ); - } - Ok(_) => { - panic!("Expected Celestia Config"); - } - Err(e) => { - panic!("Error parsing Celestia Config: {}", e) - } - } - - let mut config: HashMap = HashMap::new(); - config.insert("Param1".to_string(), "value1".to_string()); - config.insert("param2".to_string(), "Value2".to_string()); - - match InternalDAServerConfigType::from_str(openda_config_str) { - Ok(InternalDAServerConfigType::OpenDa(openda_config)) => { - assert_eq!( - openda_config, - DAServerOpenDAConfig { - scheme: OpenDAScheme::Gcs, - config, - max_segment_size: Some(2048), - } - ); - } - Ok(_) => { - panic!("Expected OpenDA Config"); + println!("exp_da_config: {}", exp_da_config); + match DAConfig::from_str(da_config_str) { + Ok(da_config) => { + assert_eq!(da_config, exp_da_config); } Err(e) => { - panic!("Error parsing OpenDA Config: {}", e) + panic!("Error parsing DA Config: {}", e) } } - - if InternalDAServerConfigType::from_str(invalid_config_str).is_err() { - } else { - panic!("Expected Error for invalid config"); - } } } diff --git a/crates/rooch-config/src/lib.rs b/crates/rooch-config/src/lib.rs index d2e604d6f5..2ba11f8f69 100644 --- a/crates/rooch-config/src/lib.rs +++ b/crates/rooch-config/src/lib.rs @@ -13,6 +13,7 @@ use rooch_types::rooch_network::{BuiltinChainID, RoochChainID, RoochNetwork}; use rooch_types::service_status::ServiceStatus; use rooch_types::service_type::ServiceType; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use std::fs::create_dir_all; use std::str::FromStr; use std::sync::Arc; @@ -34,6 +35,13 @@ pub static R_DEFAULT_BASE_DATA_DIR: Lazy = Lazy::new(|| { .join(".rooch") }); +pub enum MapConfigValueSource { + MapConfig, // Value came from the presence of a key in the map configuration + Environment, // Value came from the environment + Default, // Value came from a defined default value + None, // Value is not present in the map configuration, environment, or default value +} + pub fn rooch_config_dir() -> Result { get_rooch_config_dir().and_then(|dir| { if !dir.exists() { @@ -135,9 +143,17 @@ pub struct RoochOpt { #[clap(long, default_value_t, value_enum)] pub service_status: ServiceStatus, + /// Set quota size that defines how many requests can occur + /// before the governor middleware starts blocking requests from an IP address and + /// clients have to wait until the elements of the quota are replenished. + /// + /// **The burst_size must not be zero.** #[clap(long)] pub traffic_burst_size: Option, + /// Set the interval after which one element of the quota is replenished in seconds. + /// + /// **The interval must not be zero.** #[clap(long)] pub traffic_per_second: Option, @@ -365,3 +381,33 @@ impl ServerOpt { .unwrap_or_else(|| RoochChainID::default().chain_name()) } } + +// value order: +// 1. config map +// 2. env value +// 3. default value +pub fn retrieve_map_config_value( + map_config: &mut HashMap, + key: &str, + env_var: Option<&str>, + default_var: Option<&str>, +) -> MapConfigValueSource { + if map_config.contains_key(key) { + return MapConfigValueSource::MapConfig; + } + + if let Some(env_var) = env_var { + if let Ok(env_var_value) = std::env::var(env_var) { + // env_var exists + map_config.insert(key.to_string(), env_var_value.clone()); + return MapConfigValueSource::Environment; + } + } + + // Use the default + if let Some(default_var) = default_var { + map_config.insert(key.to_string(), default_var.to_string()); + return MapConfigValueSource::Default; + } + MapConfigValueSource::None +} diff --git a/crates/rooch-da/Cargo.toml b/crates/rooch-da/Cargo.toml index 675d69c60a..daca30afde 100644 --- a/crates/rooch-da/Cargo.toml +++ b/crates/rooch-da/Cargo.toml @@ -24,10 +24,11 @@ bcs = { workspace = true } log = { workspace = true } coerce = { workspace = true } async-trait = { workspace = true } -futures = { workspace = true } opendal = { workspace = true } +serde_yaml = { workspace = true } +tokio = { workspace = true } rooch-config = { workspace = true } -serde_yaml = { workspace = true } -xxhash-rust = { workspace = true, features = ["xxh3"] } -lz4 = { workspace = true } +rooch-types = { workspace = true } +rooch-store = { workspace = true } + diff --git a/crates/rooch-da/README.md b/crates/rooch-da/README.md index dd1f71d125..f99d483ddc 100644 --- a/crates/rooch-da/README.md +++ b/crates/rooch-da/README.md @@ -7,20 +7,24 @@ Merge to specification. ## Overview -In Rooch, DA (Data Availability) is a mechanism to ensure that the data(tx lists batch) is avail for async verification: -DA must ensure that within the challenge period, every batch is accessible to at least one honest node. +In Rooch, DA (Data Availability) is the `input` in async states verification process: + +verification: + +1. `input` + `state transition function` = `actual output` +2. compare `actual output` with `expected output` ### Target -For serving the async verification, according I/O model, we have: +1. **Equivalent to Bitcoin Consensus**: Pack DA into Bitcoin block. +2. **Self-Verifying**: Anyone could verify DA by checksum and its signature. +3. **Open**: DA could be anywhere, anyone could access it without permission. -Data producer is sequencer: DA provides the producer non-blocking writes as possible. +## Key Concepts -Data consumer is verifier: DA provides the consumer the most immediate data reads as possible. +### DA Stream -To meet our objectives, we require DA to render data visibility as rapidly as possible, -thus enabling verifiers to carry out asynchronous batch data verification after the data digests being documented on L1. -In other words, we don't have to wait for the data/digests to be written to L1 to start the verification. +[DA Stream](./docs/stream.md) is a continuous flow of data from sequencer to verifier. It is a sequence of DA Batch. ## Data Flow @@ -29,64 +33,48 @@ In other words, we don't have to wait for the data/digests to be written to L1 t In Verifier's perspective (verifier verifies tx), the data flow is as follows: 1. user submits tx to sequencer -2. sequencer batch maker buffer transactions to batch for lower average latency & gas cost -3. sequencer batch maker put to DA server +2. sequencer buffers transactions to a batch for lower average latency & gas cost +3. sequencer puts batch to DA server 4. verifier get batch from DA server by: - 1. pull stream from DA server (after booking) - 2. get batch from DA server by batch number - 3. get segment from DA backend (after being submitted to DA backend) - -### Put - -Put includes three actions: - -1. Sequencer batch maker put data to DA server -2. Sequencer batch maker put batch meta to L1 -3. DA server put data to DA backend + 1. pull DA stream from DA server (after booking) + 2. get batch from DA server by batch hash/block number + 3. get segments from DA backend (after being submitted to DA backend) -#### Sequencer to DA Server +## Roles -Sequencer put batch to DA server, blocking until DA server return response. If failed, sequencer will retry: +### Sequencer -In present, sequencer will keep retrying until success. After more DA servers(decentralized) are deployed, majority voting will be introduced. +Tx batch maker. Each sequencer maintains its own DA server. -##### Put Policy (TODO) +### DA Server -Put Policy is a policy to determine data persistence behaviour: +Has responsibilities: -1. lifecycle -2. hot/warm/cold storage -3. encode or not -4. ... +1. public DA Backend info. +2. provides Put/Get interface for DA. +3. Response to DA challenges. -Put Policy is a part of Sequencer configuration. Its principal objective is to provide a more balanced storage solution in terms of both performance and cost. +Each DA server could connect to multiple DA backends. -#### Sequencer to L1 +## DA Backend -After batch finalized, sequencer will put batch meta to L1 immediately. +The purpose of DA backend is to mitigate the single point of risk associated with DA server. DA server, +not the backend, remains the principal party responsible for data publication. Therefore, the DA server may elect to +submit data to DA backend asynchronously. -#### DA Server to DA Backend +## DA Server APIs -DA server must register on L2 with backend information and update the backend information on L2 prior to each change of backend. - -The purpose of DA backend is to mitigate the single point of risk associated with DA server. DA server, -not the backend, remains the principal party responsible for data publication. Therefore, the DA server may elect to submit data to DA backend asynchronously. - -##### Stream +### Put -DA server is obligated to pay fees to DA backend and is subject to its interface restrictions. -Particularly in the forthcoming decentralized DA server cluster, faced with a variety of different DA backend implementations, -we require the DA server to maintain flexibility and low cost in its implementation while providing a unified interface. -Rooch Network accomplishes our objectives by treating the transaction sequence as a stream and flexibly dividing it into segments: +Put includes these actions: -1. Each network has its own stream. -2. Several batch form an chunk for better compression ratio. -3. Every chunk, once compressed, will be partitioned into numerous segments to comply with the block size restrictions of the DA backend. -Simultaneously, this approach aids in augmenting parallelism. +1. Sequencer puts data to DA server +2. Sequencer packs data meta to Proposer +3. DA server put data to DA backends ### Get -There are various ways to get batch data. DA Batch could be verified by meta on L1. +There are various ways to get batch data. DA Batch could be verified by meta on Bitcoin. #### Bypass DA server accessing DA Backend directly @@ -94,7 +82,8 @@ Verifier could access DA backend directly to get data. However, it's not recomme 1. DA backend might lag behind the most recent data, given the likelihood of its data being uploaded asynchronously. 2. DA backend might be slow to respond to requests, DA server is the professional storage node. -3. DA server, accountable for data accessibility, risks forfeiture of its deposit via arbitration if it fails to meet the conditions of data availability. +3. DA server, accountable for data accessibility, risks forfeiture of its deposit via arbitration if it fails to meet + the conditions of data availability. This methodology may be employed to access data in the event that all DA servers are unable to respond appropriately. @@ -102,44 +91,6 @@ This methodology may be employed to access data in the event that all DA servers Verifier subscribe to a data stream from the DA server. -#### Get DA Batch by DA server - -DA server maintains a batch index, which is updated in real time as new batches are added. Anyone could get batch by batch number. - -#### Scaling - -Anyone can become an unpledged, non-liability DA server to facilitate horizontal scaling of data access, -with each DA server being homogeneous. Pledged nodes will receive data pushed by the sequencer, garner community rewards, -and be supervised by the community. Unpledged nodes can fetch data from other nodes; -these may be nodes operated by the Rooch network to enhance network throughput, -backup nodes established by other community participants for various needs, -or efforts made with the intention of joining the pledged network in the future. - -#### Data Integrity (TODO) - -Each batch is recorded on L1 via an accumulator. Given that the segments, post-partitioning, -are ultimately written onto the DA backend, the batches can be sufficiently large to compensate for the speed difference between L1 and L2. -Verifiers can initially trust the data from DA server optimistically, and perform verification once L1 completes the synchronization of the accumulator. -DA server will sign the data summary, and if it does not match with L1, a challenge can be initiated against DA server. - -## Roadmap - -DA is not merely a coding project, but also a community venture. Rooch Network will gradually achieve decentralized DA services in unison with the community. - -### Phase 1: Single DA Server - -Operated by the Rooch Network. - -#### As a component of Sequencer: PoC - -Using RPC to communicate with light client of DA backend directly: - -1. Offload DA details from Sequencer -2. Scaling independently of Sequencer -3. Fault isolation - -#### Independent from Sequencer - -### Phase 2: Decentralized DA Servers +#### Get DA Batch by DA server (TODO) -Data Visibility (DV) will be the acceleration component of DA. \ No newline at end of file +DA server maintains a batch index, which is updated in real time as new batches are added. Anyone could get batch. diff --git a/crates/rooch-da/docs/stream.md b/crates/rooch-da/docs/stream.md index 3fb0e184f4..62201fdfd7 100644 --- a/crates/rooch-da/docs/stream.md +++ b/crates/rooch-da/docs/stream.md @@ -3,11 +3,25 @@ DA Stream DA Stream is a continuous flow of data from sequencer to verifier. It is a sequence of DA Batch. +All efforts on DA is to maintain a single trustable DA data stream with high-performance and low cost. + +DA server is obligated to pay fees to DA backend and is subject to its interface restrictions. +Particularly in the forthcoming decentralized DA server cluster, faced with a variety of different DA backend +implementations, +we require the DA server to maintain flexibility and low cost in its implementation while providing a unified interface. +Rooch Network accomplishes our objectives by treating the transaction sequence as a stream and flexibly dividing it into +segments: + +1. Each network(e.g. main/test) has its own stream. +2. Several batch form a chunk for better compression ratio. +3. Every chunk, once compressed, will be partitioned into numerous segments to comply with the block size restrictions + of the DA backend. Simultaneously, this approach aids in augmenting parallelism. + ## Batch A batch is a collection of transactions. It is the unit of data flow in DA Stream. -Each batch maps to a L2 block. +Each batch maps to a range of tx. ## Chunk diff --git a/crates/rooch-da/src/actor/da.rs b/crates/rooch-da/src/actor/da.rs deleted file mode 100644 index 3a8a482405..0000000000 --- a/crates/rooch-da/src/actor/da.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use std::sync::{Arc, RwLock}; - -use anyhow::{anyhow, Result}; -use async_trait::async_trait; -use coerce::actor::context::ActorContext; -use coerce::actor::message::Handler; -use coerce::actor::system::ActorSystem; -use coerce::actor::{Actor, IntoActor}; -use futures::stream::FuturesUnordered; -use futures::StreamExt; - -use rooch_config::da_config::{DAConfig, InternalDAServerConfigType}; - -use crate::messages::{Batch, PutBatchInternalDAMessage}; -use crate::server::celestia::actor::server::DAServerCelestiaActor; -use crate::server::celestia::proxy::DAServerCelestiaProxy; -use crate::server::openda::actor::server::DAServerOpenDAActor; -use crate::server::openda::proxy::DAServerOpenDAProxy; -use crate::server::serverproxy::DAServerProxy; - -// TODO tx buffer for building batch -pub struct DAActor { - internal_servers: InternalServers, -} - -struct InternalServers { - servers: Arc>>>, - submit_threshold: usize, -} - -impl Actor for DAActor {} - -impl DAActor { - pub async fn new(da_config: DAConfig, actor_system: &ActorSystem) -> Result { - // internal servers - let mut servers: Vec> = Vec::new(); - let mut submit_threshold = 1; - let mut success_count = 0; - - // server config has higher priority than submit threshold - if let Some(internal_da_server_config) = &da_config.internal_da_server { - let mut server_config = internal_da_server_config.clone(); - submit_threshold = server_config.calculate_submit_threshold(); - - for server_config_type in &server_config.servers { - if let InternalDAServerConfigType::Celestia(celestia_config) = server_config_type { - let da_server = DAServerCelestiaActor::new(celestia_config) - .await - .into_actor(Some("DAServerCelestia"), actor_system) - .await?; - servers.push(Arc::new(DAServerCelestiaProxy::new( - da_server.clone().into(), - ))); - success_count += 1; - } - if let InternalDAServerConfigType::OpenDa(openda_config) = server_config_type { - let da_server = DAServerOpenDAActor::new(openda_config) - .await? - .into_actor( - Some(format!("DAServerOpenDA-{}", openda_config.scheme)), - actor_system, - ) - .await?; - servers.push(Arc::new(DAServerOpenDAProxy::new(da_server.clone().into()))); - success_count += 1; - } - } - } else { - servers.push(Arc::new(crate::server::serverproxy::DAServerNopProxy {})); - success_count += 1; - } - - if success_count < submit_threshold { - return Err(anyhow!( - "failed to start da: not enough servers for future submissions. exp>= {} act: {}", - submit_threshold, - success_count - )); - } - - Ok(Self { - internal_servers: InternalServers { - servers: Arc::new(RwLock::new(servers)), - submit_threshold, - }, - }) - } - - pub async fn submit_batch(&self, batch: Batch) -> Result<()> { - // TODO calc checksum - // TODO richer policy for multi servers - // TODO verify checksum - // TODO retry policy & log - - let servers = self.internal_servers.servers.read().unwrap().to_vec(); - let submit_threshold = self.internal_servers.submit_threshold; - - let mut futures_unordered = FuturesUnordered::new(); - for server in servers { - let server = Arc::clone(&server); - let batch = batch.clone(); - futures_unordered.push(async move { - server - .public_batch(PutBatchInternalDAMessage { - batch: batch.clone(), - }) - .await - }); - } - - let mut success_count = 0; - while let Some(result) = futures_unordered.next().await { - match result { - Ok(_) => { - success_count += 1; - if success_count >= submit_threshold { - return Ok(()); - } - } - Err(e) => { - log::warn!("{:?}, fail to submit batch to da server.", e); // TODO add da server name - } - } - } - - if success_count < submit_threshold { - Err(anyhow::Error::msg(format!( - "not enough successful submissions. exp>= {} act: {}", - submit_threshold, success_count - ))) - } else { - Ok(()) - } - } -} - -#[async_trait] -impl Handler for DAActor { - async fn handle(&mut self, msg: Batch, _ctx: &mut ActorContext) -> Result<()> { - self.submit_batch(msg).await - } -} diff --git a/crates/rooch-da/src/actor/messages.rs b/crates/rooch-da/src/actor/messages.rs new file mode 100644 index 0000000000..4819848524 --- /dev/null +++ b/crates/rooch-da/src/actor/messages.rs @@ -0,0 +1,28 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use coerce::actor::message::Message; +use rooch_types::da::batch::SignedDABatchMeta; +use rooch_types::transaction::LedgerTransaction; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PutDABatchMessage { + pub tx_order_start: u64, + pub tx_order_end: u64, + pub tx_list: Vec, +} + +impl Message for PutDABatchMessage { + type Result = anyhow::Result; +} + +impl PutDABatchMessage { + pub fn new(tx_order_start: u64, tx_order_end: u64, tx_list: Vec) -> Self { + Self { + tx_order_start, + tx_order_end, + tx_list, + } + } +} diff --git a/crates/rooch-da/src/actor/mod.rs b/crates/rooch-da/src/actor/mod.rs index a166495ec2..e20404f8fa 100644 --- a/crates/rooch-da/src/actor/mod.rs +++ b/crates/rooch-da/src/actor/mod.rs @@ -1,4 +1,5 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -pub mod da; +pub mod messages; +pub mod server; diff --git a/crates/rooch-da/src/actor/server.rs b/crates/rooch-da/src/actor/server.rs new file mode 100644 index 0000000000..16cd94709c --- /dev/null +++ b/crates/rooch-da/src/actor/server.rs @@ -0,0 +1,278 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::actor::messages::PutDABatchMessage; +use crate::backend::celestia::CelestiaBackend; +use crate::backend::openda::OpenDABackend; +use crate::backend::DABackend; +use anyhow::anyhow; +use async_trait::async_trait; +use coerce::actor::context::ActorContext; +use coerce::actor::message::Handler; +use coerce::actor::Actor; +use moveos_types::h256::H256; +use rooch_config::da_config::{DABackendConfigType, DAConfig}; +use rooch_store::da_store::DAMetaStore; +use rooch_store::transaction_store::TransactionStore; +use rooch_store::RoochStore; +use rooch_types::crypto::RoochKeyPair; +use rooch_types::da::batch::{BlockRange, DABatch, SignedDABatchMeta}; +use rooch_types::transaction::LedgerTransaction; +use std::sync::Arc; + +pub struct DAServerActor { + sequencer_key: RoochKeyPair, + rooch_store: RoochStore, + last_block_number: Option, + + nop_backend: bool, + backends: Vec>, + submit_threshold: usize, +} + +impl Actor for DAServerActor {} + +impl DAServerActor { + pub async fn new( + da_config: DAConfig, + sequencer_key: RoochKeyPair, + rooch_store: RoochStore, + last_tx_order: Option, + genesis_namespace: String, + ) -> anyhow::Result { + let mut backends: Vec> = Vec::new(); + let mut submit_threshold = 1; + let mut act_backends = 0; + + let mut nop_backend = false; + // backend config has higher priority than submit threshold + if let Some(mut backend_config) = da_config.da_backend { + submit_threshold = backend_config.calculate_submit_threshold(); + + for backend_type in &backend_config.backends { + if let DABackendConfigType::Celestia(celestia_config) = backend_type { + let backend = CelestiaBackend::new(celestia_config).await?; + backends.push(Arc::new(backend)); + act_backends += 1; + } + if let DABackendConfigType::OpenDa(openda_config) = backend_type { + let backend = + OpenDABackend::new(openda_config, genesis_namespace.clone()).await?; + backends.push(Arc::new(backend)); + act_backends += 1; + } + } + } else { + nop_backend = true; + backends.push(Arc::new(crate::backend::DABackendNopProxy {})); + act_backends += 1; + } + + if act_backends < submit_threshold { + return Err(anyhow!( + "failed to start da: not enough backends for future submissions. exp>= {} act: {}", + submit_threshold, + act_backends + )); + } + + rooch_store.catchup_submitting_blocks(last_tx_order)?; + let last_block_number = rooch_store.get_last_block_number()?; + + if let Some(last_block_number) = last_block_number { + if !nop_backend { + let background_da_server = DAServerActor { + sequencer_key: sequencer_key.copy(), + rooch_store: rooch_store.clone(), + last_block_number: Some(last_block_number), + nop_backend, + backends: backends.clone(), + submit_threshold, + }; + + tokio::spawn(async move { + if let Err(e) = background_da_server + .start_background_submit(last_block_number) + .await + { + log::error!("{:?}, fail to start background da submit.", e); + } + }); + } + } + + Ok(DAServerActor { + sequencer_key, + rooch_store, + last_block_number, + nop_backend, + backends, + submit_threshold, + }) + } + + pub async fn submit_batch( + &mut self, + msg: PutDABatchMessage, + ) -> anyhow::Result { + let tx_order_start = msg.tx_order_start; + let tx_order_end = msg.tx_order_end; + let block_number = self + .rooch_store + .append_submitting_block(self.last_block_number, tx_order_start, tx_order_end) + .unwrap_or_else(|_| panic!("fail to append submitting block: last_block_number: {:?}; new block: tx_order_start: {:?}, tx_order_end: {:?}", + self.last_block_number, tx_order_start, tx_order_end)); + + let signed_meta = self + .submit_batch_raw( + BlockRange { + block_number, + tx_order_start, + tx_order_end, + }, + msg.tx_list, + ) + .await?; + self.last_block_number = Some(block_number); + + Ok(signed_meta) + } + + // should be idempotent + async fn submit_batch_raw( + &self, + block_range: BlockRange, + tx_list: Vec, + ) -> anyhow::Result { + let block_number = block_range.block_number; + let tx_order_start = block_range.tx_order_start; + let tx_order_end = block_range.tx_order_end; + + // create batch + let batch = DABatch::new( + block_number, + tx_order_start, + tx_order_end, + &tx_list, + self.sequencer_key.copy(), + ); + let batch_meta = batch.meta.clone(); + let meta_signature = batch.meta_signature.clone(); + + // submit batch + self.submit_batch_to_backends(batch).await?; + + // update block submitting state if it's not nop-backend + // if it's nop-backend, we don't need to update submitting state, we may need to submit batch to other backends later by fetch unsubmitted blocks + if !self.nop_backend { + match self.rooch_store.set_submitting_block_done( + block_number, + tx_order_start, + tx_order_end, + ) { + Ok(_) => {} + Err(e) => { + log::warn!("{:?}, fail to set submitting block done.", e); + } + }; + }; + Ok(SignedDABatchMeta { + meta: batch_meta, + signature: meta_signature, + }) + } + + async fn submit_batch_to_backends(&self, batch: DABatch) -> anyhow::Result<()> { + let backends = self.backends.clone(); + let submit_threshold = self.submit_threshold; + // submit to backend in order until meet submit_threshold + let mut success_count = 0; + for backend in &backends { + let submit_fut = backend.submit_batch(batch.clone()); + match submit_fut.await { + Ok(_) => { + success_count += 1; + if success_count >= submit_threshold { + break; + } + } + Err(e) => { + log::warn!("{:?}, fail to submit batch to backend.", e); + } + } + } + + if success_count < submit_threshold { + return Err(anyhow!( + "not enough successful submissions. exp>= {} act: {}", + submit_threshold, + success_count + )); + }; + Ok(()) + } + + // TODO: continue to submit blocks in the background even after all blocks <= init last_block_number have been submitted + async fn start_background_submit(&self, last_block_number: u128) -> anyhow::Result<()> { + let cursor = self.rooch_store.get_background_submit_block_cursor()?; + let exp_count = if let Some(cursor) = cursor { + last_block_number - cursor + } else { + last_block_number + 1 + }; + let unsubmitted_blocks = self + .rooch_store + .get_submitting_blocks(cursor.unwrap_or(0), Some(exp_count as usize))?; + + if unsubmitted_blocks.is_empty() { + return Ok(()); // nothing to do + } + + let mut submit_count: u128 = 0; + for block in unsubmitted_blocks { + let block_number = block.block_number; + if block_number > last_block_number { + break; + } + let tx_order_start = block.tx_order_start; + let tx_order_end = block.tx_order_end; + // collect tx from start to end for rooch_store + let tx_orders: Vec = (tx_order_start..=tx_order_end).collect(); + let tx_hashes = self.rooch_store.get_tx_hashes(tx_orders)?; + let tx_hashes: Vec = tx_hashes + .into_iter() + .map(|tx_hash| tx_hash.unwrap()) + .collect(); + let mut tx_list: Vec = Vec::new(); + for tx_hash in tx_hashes { + let tx = self + .rooch_store + .get_transaction_by_hash(tx_hash)? + .unwrap_or_else(|| panic!("tx not found for hash: {:?}", tx_hash)); + tx_list.push(tx); + } + self.submit_batch_raw(block, tx_list).await?; + submit_count += 1; + if submit_count % 1024 == 0 { + // it's okay to set cursor a bit behind: submit_batch_raw set submitting block done, so it won't be submitted again after restart + self.rooch_store + .set_background_submit_block_cursor(block_number)?; + log::info!("da: submitted {} blocks in background", submit_count); + } + } + self.rooch_store + .set_background_submit_block_cursor(last_block_number)?; + Ok(()) + } +} + +#[async_trait] +impl Handler for DAServerActor { + async fn handle( + &mut self, + msg: PutDABatchMessage, + _ctx: &mut ActorContext, + ) -> anyhow::Result { + self.submit_batch(msg).await + } +} diff --git a/crates/rooch-da/src/backend/celestia/mod.rs b/crates/rooch-da/src/backend/celestia/mod.rs new file mode 100644 index 0000000000..d04266f10f --- /dev/null +++ b/crates/rooch-da/src/backend/celestia/mod.rs @@ -0,0 +1,113 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::backend::DABackend; +use async_trait::async_trait; +use celestia_rpc::{BlobClient, Client}; +use celestia_types::blob::SubmitOptions; +use celestia_types::nmt::Namespace; +use celestia_types::{Blob, Commitment}; +use rooch_config::da_config::DABackendCelestiaConfig; +use rooch_types::da::batch::DABatch; +use rooch_types::da::chunk::{Chunk, ChunkV0}; +use rooch_types::da::segment::{Segment, SegmentID}; + +// In present, celestia supports for up to 8 MB blocks, starting with 2MB at genesis and upgradeable through onchain governance. +// The max segment size is set to 1MB for now. +const DEFAULT_CELESTIA_MAX_SEGMENT_SIZE: usize = 1024 * 1024; + +pub struct CelestiaBackend { + max_segment_size: usize, + client: CelestiaClient, +} + +#[async_trait] +impl DABackend for CelestiaBackend { + async fn submit_batch(&self, batch: DABatch) -> anyhow::Result<()> { + let chunk: ChunkV0 = batch.into(); + let segments = chunk.to_segments(self.max_segment_size); + for segment in segments { + let result = self.client.submit(segment).await?; + log::info!( + "submitted segment to celestia node, segment_id: {:?}, namespace: {:?}, commitment: {:?}, height: {}", + result.segment_id, + result.namespace, + result.commitment, + result.height, + ); + } + + Ok(()) + } +} + +impl CelestiaBackend { + pub async fn new(cfg: &DABackendCelestiaConfig) -> anyhow::Result { + let max_segment_size = cfg + .max_segment_size + .unwrap_or(DEFAULT_CELESTIA_MAX_SEGMENT_SIZE); + let client = CelestiaClient::new(cfg.namespace, &cfg.conn, &cfg.auth_token).await?; + + Ok(CelestiaBackend { + max_segment_size, + client, + }) + } +} + +struct CelestiaClient { + namespace: Namespace, + client: Client, +} + +pub struct SubmitBackendResult { + pub segment_id: SegmentID, + pub namespace: Namespace, + pub height: u64, + pub commitment: Commitment, +} + +impl CelestiaClient { + pub async fn new( + namespace: Namespace, + conn_str: &str, + auth_token: &str, + ) -> anyhow::Result { + let celestia_client = Client::new(conn_str, Option::from(auth_token)).await?; + Ok(CelestiaClient { + namespace, + client: celestia_client, + }) + } + + pub async fn submit( + &self, + segment: Box, + ) -> anyhow::Result { + let data = segment.to_bytes(); + let blob = Blob::new(self.namespace, data)?; + let segment_id = segment.get_id(); + // TODO backoff retry + match self + .client + .blob_submit(&[blob.clone()], SubmitOptions::default()) + .await + { + Ok(height) => Ok(SubmitBackendResult { + segment_id, + namespace: self.namespace, + height, + commitment: blob.commitment, + }), + Err(e) => { + log::warn!( + "failed to submit segment to celestia node, segment_id: {:?}, commitment: {:?}, error:{:?}", + segment_id, + blob.commitment, + e, + ); + Err(e.into()) + } + } + } +} diff --git a/crates/rooch-da/src/backend/mod.rs b/crates/rooch-da/src/backend/mod.rs new file mode 100644 index 0000000000..45d288d43e --- /dev/null +++ b/crates/rooch-da/src/backend/mod.rs @@ -0,0 +1,23 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use rooch_types::da::batch::DABatch; + +pub mod celestia; +pub mod openda; + +#[async_trait] +pub trait DABackend: Sync + Send { + async fn submit_batch(&self, batch: DABatch) -> anyhow::Result<()>; +} + +// DABackendNopProxy is a no-op implementation of DABackendProxy +pub struct DABackendNopProxy; + +#[async_trait] +impl DABackend for DABackendNopProxy { + async fn submit_batch(&self, _batch: DABatch) -> anyhow::Result<()> { + Ok(()) + } +} diff --git a/crates/rooch-da/src/server/openda/actor/server.rs b/crates/rooch-da/src/backend/openda/mod.rs similarity index 63% rename from crates/rooch-da/src/server/openda/actor/server.rs rename to crates/rooch-da/src/backend/openda/mod.rs index 06b0a19d64..9367cc60a3 100644 --- a/crates/rooch-da/src/server/openda/actor/server.rs +++ b/crates/rooch-da/src/backend/openda/mod.rs @@ -1,61 +1,56 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -use anyhow::{anyhow, Result}; +use crate::backend::DABackend; +use anyhow::anyhow; use async_trait::async_trait; -use coerce::actor::context::ActorContext; -use coerce::actor::message::Handler; -use coerce::actor::Actor; use opendal::layers::{LoggingLayer, RetryLayer}; use opendal::{Operator, Scheme}; -use rooch_config::config::retrieve_map_config_value; +use rooch_config::da_config::{DABackendOpenDAConfig, OpenDAScheme}; +use rooch_config::retrieve_map_config_value; +use rooch_types::da::batch::DABatch; +use rooch_types::da::chunk::{Chunk, ChunkV0}; +use rooch_types::da::segment::SegmentID; use std::collections::HashMap; use std::path::Path; -use crate::chunk::{Chunk, ChunkV0}; -use rooch_config::da_config::{DAServerOpenDAConfig, OpenDAScheme}; +pub const DEFAULT_MAX_SEGMENT_SIZE: u64 = 4 * 1024 * 1024; +pub const DEFAULT_MAX_RETRY_TIMES: usize = 4; -use crate::messages::PutBatchInternalDAMessage; -use crate::segment::SegmentID; +#[async_trait] +impl DABackend for OpenDABackend { + async fn submit_batch(&self, batch: DABatch) -> anyhow::Result<()> { + self.pub_batch(batch).await + } +} -pub struct DAServerOpenDAActor { +pub struct OpenDABackend { + prefix: String, + scheme: OpenDAScheme, max_segment_size: usize, operator: Operator, } -pub const CHUNK_V0_PREFIX: &str = "chunk_v0"; -pub const DEFAULT_MAX_SEGMENT_SIZE: u64 = 4 * 1024 * 1024; -pub const DEFAULT_MAX_RETRY_TIMES: usize = 4; - -impl Actor for DAServerOpenDAActor {} - -impl DAServerOpenDAActor { - pub async fn new(cfg: &DAServerOpenDAConfig) -> Result { +impl OpenDABackend { + pub async fn new( + cfg: &DABackendOpenDAConfig, + genesis_namespace: String, + ) -> anyhow::Result { let mut config = cfg.clone(); let op: Operator = match config.scheme { OpenDAScheme::Fs => { // root must be existed - if !config.config.contains_key("root") { - return Err(anyhow!( - "key 'root' must be existed in config for scheme {:?}", - OpenDAScheme::Fs - )); - } + check_config_exist(OpenDAScheme::Fs, &config.config, "root")?; new_retry_operator(Scheme::Fs, config.config, None).await? } OpenDAScheme::Gcs => { - // If certain keys don't exist in the map, set them from environment - if !config.config.contains_key("bucket") { - if let Ok(bucket) = std::env::var("OPENDA_GCS_BUCKET") { - config.config.insert("bucket".to_string(), bucket); - } - } - if !config.config.contains_key("root") { - if let Ok(root) = std::env::var("OPENDA_GCS_ROOT") { - config.config.insert("root".to_string(), root); - } - } + retrieve_map_config_value( + &mut config.config, + "bucket", + Some("OPENDA_GCS_BUCKET"), + Some("rooch-openda-dev"), + ); if !config.config.contains_key("credential") { if let Ok(credential) = std::env::var("OPENDA_GCS_CREDENTIAL") { config.config.insert("credential".to_string(), credential); @@ -84,7 +79,7 @@ impl DAServerOpenDAActor { &mut config.config, "default_storage_class", Some("OPENDA_GCS_DEFAULT_STORAGE_CLASS"), - "STANDARD", + Some("STANDARD"), ); check_config_exist(OpenDAScheme::Gcs, &config.config, "bucket")?; @@ -100,41 +95,53 @@ impl DAServerOpenDAActor { (Err(_), Ok(_)) => (), (Err(_), Err(_)) => { - return Err(anyhow!("either 'credential' or 'credential_path' must exist in config for scheme {:?}", OpenDAScheme::Gcs)); + return Err(anyhow!( + "credential no found in config for scheme {:?}", + OpenDAScheme::Gcs + )); } } // After setting defaults, proceed with creating Operator new_retry_operator(Scheme::Gcs, config.config, None).await? } - _ => Err(anyhow!("unsupported open-da scheme: {:?}", config.scheme))?, + OpenDAScheme::S3 => { + todo!("s3 backend is not implemented yet"); + } }; Ok(Self { + prefix: config.namespace.unwrap_or(genesis_namespace), + scheme: config.scheme, max_segment_size: cfg.max_segment_size.unwrap_or(DEFAULT_MAX_SEGMENT_SIZE) as usize, operator: op, }) } - pub async fn pub_batch(&self, batch_msg: PutBatchInternalDAMessage) -> Result<()> { - let chunk: ChunkV0 = batch_msg.batch.into(); - let segments = chunk.to_segments(self.max_segment_size); + pub async fn pub_batch(&self, batch: DABatch) -> anyhow::Result<()> { + let chunk: ChunkV0 = batch.into(); + + let prefix = self.prefix.clone(); + let max_segment_size = self.max_segment_size; + let segments = chunk.to_segments(max_segment_size); for segment in segments { let bytes = segment.to_bytes(); match self - .write_segment(segment.get_id(), bytes, CHUNK_V0_PREFIX.to_string()) + .write_segment(segment.get_id(), bytes, Some(prefix.clone())) .await { Ok(_) => { log::info!( - "submitted segment to open-da node, segment: {:?}", + "submitted segment to open-da scheme: {:?}, segment_id: {:?}", + self.scheme, segment.get_id(), ); } Err(e) => { log::warn!( - "failed to submit segment to open-da node, segment_id: {:?}, error:{:?}", + "failed to submit segment to open-da scheme: {:?}, segment_id: {:?}, error:{:?}", + self.scheme, segment.get_id(), e, ); @@ -150,9 +157,12 @@ impl DAServerOpenDAActor { &self, segment_id: SegmentID, segment_bytes: Vec, - prefix: String, - ) -> Result<()> { - let path = format!("{}/{}", prefix, segment_id); + prefix: Option, + ) -> anyhow::Result<()> { + let path = match prefix { + Some(prefix) => format!("{}/{}", prefix, segment_id), + None => segment_id.to_string(), + }; let mut w = self.operator.writer(&path).await?; w.write(segment_bytes).await?; w.close().await?; @@ -164,7 +174,7 @@ fn check_config_exist( scheme: OpenDAScheme, config: &HashMap, key: &str, -) -> Result<()> { +) -> anyhow::Result<()> { if config.contains_key(key) { Ok(()) } else { @@ -180,7 +190,7 @@ async fn new_retry_operator( scheme: Scheme, config: HashMap, max_retry_times: Option, -) -> Result { +) -> anyhow::Result { let mut op = Operator::via_map(scheme, config)?; let max_times = max_retry_times.unwrap_or(DEFAULT_MAX_RETRY_TIMES); op = op @@ -189,14 +199,3 @@ async fn new_retry_operator( op.check().await?; Ok(op) } - -#[async_trait] -impl Handler for DAServerOpenDAActor { - async fn handle( - &mut self, - msg: PutBatchInternalDAMessage, - _ctx: &mut ActorContext, - ) -> Result<()> { - self.pub_batch(msg).await - } -} diff --git a/crates/rooch-da/src/lib.rs b/crates/rooch-da/src/lib.rs index 18af348be9..0edb2d3233 100644 --- a/crates/rooch-da/src/lib.rs +++ b/crates/rooch-da/src/lib.rs @@ -2,8 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 pub mod actor; -pub mod chunk; -pub mod messages; +pub mod backend; pub mod proxy; -pub mod segment; -pub mod server; diff --git a/crates/rooch-da/src/messages.rs b/crates/rooch-da/src/messages.rs deleted file mode 100644 index 624684f136..0000000000 --- a/crates/rooch-da/src/messages.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use coerce::actor::message::Message; -use serde::{Deserialize, Serialize}; - -use moveos_types::h256::H256; - -/// The batch in Rooch is constructed by the batch submitter, representing a batch of transactions, mapping to a L2 block -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub struct Batch { - /// each batch maps to a L2 block - pub block_number: u128, - /// How many transactions in the batch - pub tx_count: u64, - /// The previous tx accumulator root of the block - pub prev_tx_accumulator_root: H256, - /// The tx accumulator root after the last transaction append to the accumulator - pub tx_accumulator_root: H256, - - /// sha256h of data - pub batch_hash: H256, - /// encoded tx(LedgerTransaction) list - pub data: Vec, -} - -impl Message for Batch { - type Result = Result<()>; -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct PutBatchInternalDAMessage { - pub batch: Batch, - // TODO add put policy -} - -impl Message for PutBatchInternalDAMessage { - type Result = Result<()>; -} diff --git a/crates/rooch-da/src/proxy/mod.rs b/crates/rooch-da/src/proxy/mod.rs index c779b13f7c..676c23c580 100644 --- a/crates/rooch-da/src/proxy/mod.rs +++ b/crates/rooch-da/src/proxy/mod.rs @@ -1,22 +1,22 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 +use crate::actor::messages::PutDABatchMessage; +use crate::actor::server::DAServerActor; use coerce::actor::ActorRef; - -use crate::actor::da::DAActor; -use crate::messages::Batch; +use rooch_types::da::batch::SignedDABatchMeta; #[derive(Clone)] -pub struct DAProxy { - pub actor: ActorRef, +pub struct DAServerProxy { + pub actor: ActorRef, } -impl DAProxy { - pub fn new(actor: ActorRef) -> Self { +impl DAServerProxy { + pub fn new(actor: ActorRef) -> Self { Self { actor } } - pub async fn submit_batch(&self, batch: Batch) -> anyhow::Result<()> { - self.actor.send(batch).await? + pub async fn pub_batch(&self, msg: PutDABatchMessage) -> anyhow::Result { + self.actor.send(msg).await? } } diff --git a/crates/rooch-da/src/server/README.md b/crates/rooch-da/src/server/README.md deleted file mode 100644 index 4f5de70cfd..0000000000 --- a/crates/rooch-da/src/server/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Internal DA Server -================== - -This crate contains the internal DA server which is inside the Rooch server. \ No newline at end of file diff --git a/crates/rooch-da/src/server/celestia/README.md b/crates/rooch-da/src/server/celestia/README.md deleted file mode 100644 index bff30a9e5c..0000000000 --- a/crates/rooch-da/src/server/celestia/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Celestia Server - -DA Server implementation of using Celestia as DA backend. \ No newline at end of file diff --git a/crates/rooch-da/src/server/celestia/actor/server.rs b/crates/rooch-da/src/server/celestia/actor/server.rs deleted file mode 100644 index dad211ae30..0000000000 --- a/crates/rooch-da/src/server/celestia/actor/server.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use async_trait::async_trait; -use celestia_types::nmt::Namespace; -use coerce::actor::context::ActorContext; -use coerce::actor::message::Handler; -use coerce::actor::Actor; - -use crate::chunk::{Chunk, ChunkV0}; -use rooch_config::da_config::DAServerCelestiaConfig; - -use crate::messages::PutBatchInternalDAMessage; -use crate::server::celestia::backend::Backend; - -pub struct DAServerCelestiaActor { - max_segment_size: usize, - backend: Backend, -} - -impl Actor for DAServerCelestiaActor {} - -impl DAServerCelestiaActor { - pub async fn new(cfg: &DAServerCelestiaConfig) -> Self { - let namespace_str = cfg.namespace.as_ref().unwrap().clone(); - let namespace: Namespace = serde_yaml::from_str(&namespace_str).unwrap(); - let conn_str = cfg.conn.as_ref().unwrap().clone(); - let token = cfg.auth_token.as_ref().unwrap().clone(); - - Self { - max_segment_size: cfg.max_segment_size.unwrap() as usize, - backend: Backend::new(namespace, &conn_str, &token).await, - } - } - - pub async fn public_batch(&self, batch_msg: PutBatchInternalDAMessage) -> Result<()> { - let chunk: ChunkV0 = batch_msg.batch.into(); - let segments = chunk.to_segments(self.max_segment_size); - for segment in segments { - let result = self.backend.submit(segment).await?; - log::info!( - "submitted segment to celestia node, segment_id: {:?}, namespace: {:?}, commitment: {:?}, height: {}", - result.segment_id, - result.namespace, - result.commitment, - result.height, - ); - } - - Ok(()) - } -} - -#[async_trait] -impl Handler for DAServerCelestiaActor { - async fn handle( - &mut self, - msg: PutBatchInternalDAMessage, - _ctx: &mut ActorContext, - ) -> Result<()> { - self.public_batch(msg).await - } -} diff --git a/crates/rooch-da/src/server/celestia/backend.rs b/crates/rooch-da/src/server/celestia/backend.rs deleted file mode 100644 index ae1df33d3d..0000000000 --- a/crates/rooch-da/src/server/celestia/backend.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use celestia_rpc::{BlobClient, Client}; -use celestia_types::blob::SubmitOptions; -use celestia_types::nmt::Namespace; -use celestia_types::{Blob, Commitment}; - -use crate::segment::{Segment, SegmentID}; - -pub struct Backend { - namespace: Namespace, - client: Client, -} - -pub struct SubmitBackendResult { - pub segment_id: SegmentID, - pub namespace: Namespace, - pub height: u64, - pub commitment: Commitment, -} - -impl Backend { - pub async fn new(namespace: Namespace, conn_str: &str, auth_token: &str) -> Self { - let celestia_client = Client::new(conn_str, Option::from(auth_token)) - .await - .unwrap(); - Self { - namespace, - client: celestia_client, - } - } - - pub async fn submit(&self, segment: Box) -> Result { - let data = segment.to_bytes(); - let blob = Blob::new(self.namespace, data).unwrap(); - let segment_id = segment.get_id(); - - // TODO tx manager - // TODO backoff retry - match self - .client - .blob_submit(&[blob.clone()], SubmitOptions::default()) - .await - { - Ok(height) => Ok(SubmitBackendResult { - segment_id, - namespace: self.namespace, - height, - commitment: blob.commitment, - }), - Err(e) => { - log::warn!( - "failed to submit segment to celestia node, segment_id: {:?}, commitment: {:?}, error:{:?}", - segment_id, - blob.commitment, - e, - ); - Err(e.into()) - } - } - } -} diff --git a/crates/rooch-da/src/server/celestia/mod.rs b/crates/rooch-da/src/server/celestia/mod.rs deleted file mode 100644 index cdb4ad6f9e..0000000000 --- a/crates/rooch-da/src/server/celestia/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -pub mod actor; -mod backend; -pub mod proxy; diff --git a/crates/rooch-da/src/server/celestia/proxy/mod.rs b/crates/rooch-da/src/server/celestia/proxy/mod.rs deleted file mode 100644 index 8fc59e1b39..0000000000 --- a/crates/rooch-da/src/server/celestia/proxy/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use async_trait::async_trait; -use coerce::actor::ActorRef; - -use crate::messages::PutBatchInternalDAMessage; -use crate::server::celestia::actor::server::DAServerCelestiaActor; -use crate::server::serverproxy::DAServerProxy; - -#[derive(Clone)] -pub struct DAServerCelestiaProxy { - pub actor: ActorRef, -} - -impl DAServerCelestiaProxy { - pub fn new(actor: ActorRef) -> Self { - Self { actor } - } - - pub async fn submit_batch(&self, msg: PutBatchInternalDAMessage) -> anyhow::Result<()> { - self.actor.send(msg).await? - } -} - -#[async_trait] -impl DAServerProxy for DAServerCelestiaProxy { - async fn public_batch(&self, msg: PutBatchInternalDAMessage) -> anyhow::Result<()> { - self.submit_batch(msg).await - } -} diff --git a/crates/rooch-da/src/server/mod.rs b/crates/rooch-da/src/server/mod.rs deleted file mode 100644 index db57631e4f..0000000000 --- a/crates/rooch-da/src/server/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -pub mod celestia; -pub mod openda; -pub mod serverproxy; diff --git a/crates/rooch-da/src/server/openda/actor/mod.rs b/crates/rooch-da/src/server/openda/actor/mod.rs deleted file mode 100644 index 83afd4d573..0000000000 --- a/crates/rooch-da/src/server/openda/actor/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -pub mod server; diff --git a/crates/rooch-da/src/server/openda/mod.rs b/crates/rooch-da/src/server/openda/mod.rs deleted file mode 100644 index c6dbf6b1fd..0000000000 --- a/crates/rooch-da/src/server/openda/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -pub mod actor; -pub mod proxy; diff --git a/crates/rooch-da/src/server/openda/proxy/mod.rs b/crates/rooch-da/src/server/openda/proxy/mod.rs deleted file mode 100644 index 068e271ce9..0000000000 --- a/crates/rooch-da/src/server/openda/proxy/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use crate::messages::PutBatchInternalDAMessage; -use crate::server::openda::actor::server::DAServerOpenDAActor; -use crate::server::serverproxy::DAServerProxy; -use async_trait::async_trait; -use coerce::actor::ActorRef; - -#[derive(Clone)] -pub struct DAServerOpenDAProxy { - pub actor: ActorRef, -} - -impl DAServerOpenDAProxy { - pub fn new(actor: ActorRef) -> Self { - Self { actor } - } - - pub async fn submit_batch(&self, msg: PutBatchInternalDAMessage) -> anyhow::Result<()> { - self.actor.send(msg).await? - } -} - -#[async_trait] -impl DAServerProxy for DAServerOpenDAProxy { - async fn public_batch(&self, msg: PutBatchInternalDAMessage) -> anyhow::Result<()> { - self.submit_batch(msg).await - } -} diff --git a/crates/rooch-da/src/server/serverproxy.rs b/crates/rooch-da/src/server/serverproxy.rs deleted file mode 100644 index 590b4ba0ec..0000000000 --- a/crates/rooch-da/src/server/serverproxy.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use async_trait::async_trait; - -use crate::messages::PutBatchInternalDAMessage; - -#[async_trait] -pub trait DAServerProxy: Sync + Send { - async fn public_batch(&self, request: PutBatchInternalDAMessage) -> Result<()>; -} - -// DAServerNopProxy is a no-op implementation of DAServerProxy -pub struct DAServerNopProxy; - -#[async_trait] -impl DAServerProxy for DAServerNopProxy { - async fn public_batch(&self, _request: PutBatchInternalDAMessage) -> Result<()> { - Ok(()) - } -} diff --git a/crates/rooch-db/src/lib.rs b/crates/rooch-db/src/lib.rs index 2be4ac33c5..88eb0ab802 100644 --- a/crates/rooch-db/src/lib.rs +++ b/crates/rooch-db/src/lib.rs @@ -68,7 +68,7 @@ impl RoochDB { column_families.append(&mut rooch_store::StoreMeta::get_column_family_names().to_vec()); //ensure no duplicate column families { - let mut set = HashSet::new(); + let mut set = HashSet::with_capacity(column_families.len()); column_families.iter().for_each(|cf| { if !set.insert(cf) { panic!("Duplicate column family: {}", cf); diff --git a/crates/rooch-executor/Cargo.toml b/crates/rooch-executor/Cargo.toml index e41dfdd3be..33d1a84186 100644 --- a/crates/rooch-executor/Cargo.toml +++ b/crates/rooch-executor/Cargo.toml @@ -35,4 +35,3 @@ rooch-types = { workspace = true } rooch-genesis = { workspace = true } rooch-event = { workspace = true } rooch-store = { workspace = true } -hex = "0.4.3" diff --git a/crates/rooch-framework-tests/src/tests/multisign_account_tests.rs b/crates/rooch-framework-tests/src/tests/multisign_account_tests.rs index 4da64c9184..a73d37a0a1 100644 --- a/crates/rooch-framework-tests/src/tests/multisign_account_tests.rs +++ b/crates/rooch-framework-tests/src/tests/multisign_account_tests.rs @@ -112,7 +112,7 @@ async fn test_multisign_account_random() { let binding_test = binding_test::RustBindingTest::new().unwrap(); let count = rand::thread_rng().gen_range(3..10); - let mut pubkeys = Vec::new(); + let mut pubkeys = Vec::with_capacity(count); for _ in 0..count { let kp = RoochKeyPair::generate_secp256k1(); pubkeys.push(kp.bitcoin_public_key().unwrap().to_bytes()); diff --git a/crates/rooch-key/src/keystore/base_keystore.rs b/crates/rooch-key/src/keystore/base_keystore.rs index b544cb60af..0920addfb9 100644 --- a/crates/rooch-key/src/keystore/base_keystore.rs +++ b/crates/rooch-key/src/keystore/base_keystore.rs @@ -239,7 +239,7 @@ impl AccountKeystore for BaseKeyStore { fn addresses(&self) -> Vec { // Create an empty Vec to store the addresses. - let mut addresses = Vec::new(); + let mut addresses = Vec::with_capacity(self.keys.len() + self.session_keys.len()); // Iterate over the `keys` and `session_keys` BTreeMaps. for key in self.keys.keys() { diff --git a/crates/rooch-key/src/keystore/file_keystore.rs b/crates/rooch-key/src/keystore/file_keystore.rs index b491540294..1f7668e183 100644 --- a/crates/rooch-key/src/keystore/file_keystore.rs +++ b/crates/rooch-key/src/keystore/file_keystore.rs @@ -106,7 +106,8 @@ impl AccountKeystore for FileBasedKeystore { fn addresses(&self) -> Vec { // Create an empty Vec to store the addresses. - let mut addresses = Vec::new(); + let mut addresses = + Vec::with_capacity(self.keystore.keys.len() + self.keystore.session_keys.len()); // Iterate over the `keys` and `session_keys` BTreeMaps. for key in self.keystore.keys.keys() { diff --git a/crates/rooch-key/src/keystore/memory_keystore.rs b/crates/rooch-key/src/keystore/memory_keystore.rs index 862e518057..f9629233bf 100644 --- a/crates/rooch-key/src/keystore/memory_keystore.rs +++ b/crates/rooch-key/src/keystore/memory_keystore.rs @@ -81,7 +81,8 @@ impl AccountKeystore for InMemKeystore { fn addresses(&self) -> Vec { // Create an empty Vec to store the addresses. - let mut addresses = Vec::new(); + let mut addresses = + Vec::with_capacity(self.keystore.keys.len() + self.keystore.session_keys.len()); // Iterate over the `keys` and `session_keys` BTreeMaps. for key in self.keystore.keys.keys() { diff --git a/crates/rooch-open-rpc-macros/src/lib.rs b/crates/rooch-open-rpc-macros/src/lib.rs index 9e35ea904a..b1ae290c7a 100644 --- a/crates/rooch-open-rpc-macros/src/lib.rs +++ b/crates/rooch-open-rpc-macros/src/lib.rs @@ -49,7 +49,7 @@ pub fn open_rpc(attr: TokenStream, item: TokenStream) -> TokenStream { let name = &method.name; let deprecated = method.deprecated; let doc = &method.doc; - let mut inputs = Vec::new(); + let mut inputs = Vec::with_capacity(method.params.len()); for (name, ty, description) in &method.params { let (ty, required) = extract_type_from_option(ty.clone()); let description = if let Some(description) = description { diff --git a/crates/rooch-open-rpc-spec/schemas/openrpc.json b/crates/rooch-open-rpc-spec/schemas/openrpc.json index 406d5cfd36..ab5f52a400 100644 --- a/crates/rooch-open-rpc-spec/schemas/openrpc.json +++ b/crates/rooch-open-rpc-spec/schemas/openrpc.json @@ -12,7 +12,7 @@ "name": "Apache-2.0", "url": "https://raw.githubusercontent.com/rooch-network/rooch/main/LICENSE" }, - "version": "0.7.2" + "version": "0.7.3" }, "methods": [ { diff --git a/crates/rooch-oracle/src/data_process.rs b/crates/rooch-oracle/src/data_process.rs index 0596854b6f..650c3edb9f 100644 --- a/crates/rooch-oracle/src/data_process.rs +++ b/crates/rooch-oracle/src/data_process.rs @@ -70,7 +70,7 @@ pub fn subscribe_websocket( } Err(e) => { error!("Failed to read message: {}", e); - return; + break; } } } diff --git a/crates/rooch-proposer/src/actor/proposer.rs b/crates/rooch-proposer/src/actor/proposer.rs index 7dce391c32..c830bb31ed 100644 --- a/crates/rooch-proposer/src/actor/proposer.rs +++ b/crates/rooch-proposer/src/actor/proposer.rs @@ -1,15 +1,14 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 +use crate::metrics::ProposerMetrics; use anyhow::Result; use async_trait::async_trait; use coerce::actor::{context::ActorContext, message::Handler, Actor}; use prometheus::Registry; -use std::sync::Arc; - -use crate::metrics::ProposerMetrics; -use rooch_da::proxy::DAProxy; +use rooch_da::proxy::DAServerProxy; use rooch_types::crypto::RoochKeyPair; +use std::sync::Arc; use crate::scc::StateCommitmentChain; @@ -25,7 +24,7 @@ pub struct ProposerActor { } impl ProposerActor { - pub fn new(proposer_key: RoochKeyPair, da_proxy: DAProxy, registry: &Registry) -> Self { + pub fn new(proposer_key: RoochKeyPair, da_proxy: DAServerProxy, registry: &Registry) -> Self { Self { proposer_key, scc: StateCommitmentChain::new(da_proxy), diff --git a/crates/rooch-proposer/src/scc/mod.rs b/crates/rooch-proposer/src/scc/mod.rs index e59a8e8a5c..661fe41f94 100644 --- a/crates/rooch-proposer/src/scc/mod.rs +++ b/crates/rooch-proposer/src/scc/mod.rs @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 use crate::actor::messages::TransactionProposeMessage; -use moveos_types::h256; use moveos_types::h256::H256; -use rooch_da::messages::Batch; -use rooch_da::proxy::DAProxy; +use rooch_da::actor::messages::PutDABatchMessage; +use rooch_da::proxy::DAServerProxy; use rooch_types::block::Block; +use rooch_types::transaction::LedgerTransaction; /// State Commitment Chain(SCC) is a chain of transaction state root /// This SCC is a mirror of the on-chain SCC @@ -14,12 +14,12 @@ pub struct StateCommitmentChain { //TODO save to the storage last_block: Option, buffer: Vec, - da: DAProxy, + da: DAServerProxy, } impl StateCommitmentChain { /// Create a new SCC - pub fn new(da_proxy: DAProxy) -> Self { + pub fn new(da_proxy: DAServerProxy) -> Self { Self { last_block: None, buffer: Vec::new(), @@ -77,24 +77,30 @@ impl StateCommitmentChain { // submit batch to DA server // TODO move batch submit out of proposer - let batch_data: Vec = self.buffer.iter().flat_map(|tx| tx.tx.encode()).collect(); - let batch_hash = h256::sha2_256_of(&batch_data); - if let Err(e) = self + let tx_list: Vec = self.buffer.iter().map(|tx| tx.tx.clone()).collect(); + let batch_meta = self .da - .submit_batch(Batch { - block_number, - tx_count: batch_size, - prev_tx_accumulator_root, - tx_accumulator_root, - batch_hash, - data: batch_data, + .pub_batch(PutDABatchMessage { + tx_order_start: tx_list + .first() + .expect("tx list must not empty") + .sequence_info + .tx_order, + tx_order_end: latest_transaction.tx.sequence_info.tx_order, + tx_list, }) - .await - { - log::error!("submit batch to DA server failed: {}", e); - return None; + .await; + match batch_meta { + Ok(batch_meta) => { + log::info!("submit batch to DA success: {:?}", batch_meta); + } + Err(e) => { + log::error!("submit batch to DA failed: {:?}", e); + } } + // even if the batch submission failed, new block must have been created(otherwise panic) + // TODO update block struct and add propose logic let new_block = Block::new( block_number, batch_size, diff --git a/crates/rooch-rpc-api/src/jsonrpc_types/btc/utxo.rs b/crates/rooch-rpc-api/src/jsonrpc_types/btc/utxo.rs index 5feacd61b3..211a07211c 100644 --- a/crates/rooch-rpc-api/src/jsonrpc_types/btc/utxo.rs +++ b/crates/rooch-rpc-api/src/jsonrpc_types/btc/utxo.rs @@ -117,7 +117,8 @@ impl UTXOView { // reversed bytes of txid let bitcoin_txid = Txid::from_byte_array(utxo.txid.into_bytes()); - let mut seals_view: HashMap> = HashMap::new(); + let mut seals_view: HashMap> = + HashMap::with_capacity(utxo.seals.len()); utxo.seals.data.into_iter().for_each(|element| { seals_view.insert( element.key.to_string(), diff --git a/crates/rooch-rpc-server/Cargo.toml b/crates/rooch-rpc-server/Cargo.toml index 4b560d217e..ea8a49212d 100644 --- a/crates/rooch-rpc-server/Cargo.toml +++ b/crates/rooch-rpc-server/Cargo.toml @@ -57,4 +57,4 @@ rooch-db = { workspace = true } rooch-open-rpc = { workspace = true } rooch-open-rpc-spec-builder = { workspace = true } rooch-event = { workspace = true } -futures = "0.3.30" \ No newline at end of file +futures = "0.3.31" \ No newline at end of file diff --git a/crates/rooch-rpc-server/src/lib.rs b/crates/rooch-rpc-server/src/lib.rs index 6a02e84d08..01bc3f9ef9 100644 --- a/crates/rooch-rpc-server/src/lib.rs +++ b/crates/rooch-rpc-server/src/lib.rs @@ -16,10 +16,11 @@ use coerce::actor::{system::ActorSystem, IntoActor}; use jsonrpsee::RpcModule; use moveos_eventbus::bus::EventBus; use raw_store::errors::RawStoreError; +use rooch_config::da_config::derive_genesis_namespace; use rooch_config::server_config::ServerConfig; use rooch_config::{RoochOpt, ServerOpt}; -use rooch_da::actor::da::DAActor; -use rooch_da::proxy::DAProxy; +use rooch_da::actor::server::DAServerActor; +use rooch_da::proxy::DAServerProxy; use rooch_db::RoochDB; use rooch_event::actor::EventActor; use rooch_executor::actor::executor::ExecutorActor; @@ -283,7 +284,7 @@ pub async fn run_start_server(opt: RoochOpt, server_opt: ServerOpt) -> Result Result>, ) -> Result { - // The sequencer info would be inited when genesis, so the sequencer info should not be None + // The sequencer info would be initialized when genesis, so the sequencer info should not be None let last_sequencer_info = rooch_store .get_meta_store() .get_sequencer_info()? @@ -155,6 +155,7 @@ impl SequencerActor { ); let sequencer_info = SequencerInfo::new(tx.sequence_info.tx_order, tx_accumulator_info); + // TODO sequencer_info & tx should be saved in a transaction self.rooch_store .save_sequencer_info(sequencer_info.clone())?; self.rooch_store.save_transaction(tx.clone())?; diff --git a/crates/rooch-store/Cargo.toml b/crates/rooch-store/Cargo.toml index 186f8796c0..9eac03e330 100644 --- a/crates/rooch-store/Cargo.toml +++ b/crates/rooch-store/Cargo.toml @@ -20,8 +20,10 @@ prometheus = { workspace = true } tokio = { workspace = true } raw-store = { workspace = true } +accumulator = { workspace = true } + moveos-config = { workspace = true } moveos-types = { workspace = true } -accumulator = { workspace = true } +moveos-common = { workspace = true } rooch-types = { workspace = true } \ No newline at end of file diff --git a/crates/rooch-store/src/da_store/mod.rs b/crates/rooch-store/src/da_store/mod.rs new file mode 100644 index 0000000000..2c3d654ea8 --- /dev/null +++ b/crates/rooch-store/src/da_store/mod.rs @@ -0,0 +1,278 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::{DA_BLOCK_CURSOR_COLUMN_FAMILY_NAME, DA_BLOCK_SUBMIT_STATE_COLUMN_FAMILY_NAME}; +use raw_store::{derive_store, CodecKVStore, CodecWriteBatch}; +use rooch_types::da::batch::{BlockRange, BlockSubmitState}; +use std::cmp::min; + +pub const SUBMITTING_BLOCKS_PAGE_SIZE: usize = 1024; +pub const MAX_TXS_PER_BLOCK_IN_FIX: usize = 8192; // avoid OOM when fix submitting blocks after collapse + +pub const BACKGROUND_SUBMIT_BLOCK_CURSOR_KEY: &str = "background_submit_block_cursor"; +pub const LAST_BLOCK_NUMBER_KEY: &str = "last_block_number"; + +derive_store!( + DABlockSubmitStateStore, + u128, + BlockSubmitState, + DA_BLOCK_SUBMIT_STATE_COLUMN_FAMILY_NAME +); + +derive_store!( + DABlockCursorStore, + String, + u128, + DA_BLOCK_CURSOR_COLUMN_FAMILY_NAME +); + +pub trait DAMetaStore { + /// Get submitting blocks from start_block(inclusive) with expected count until the end of submitting blocks + fn get_submitting_blocks( + &self, + start_block: u128, + exp_count: Option, + ) -> anyhow::Result>; + fn append_submitting_block( + &self, + last_block_number: Option, + tx_order_start: u64, + tx_order_end: u64, + ) -> anyhow::Result; + fn set_submitting_block_done( + &self, + block_number: u128, + tx_order_start: u64, + tx_order_end: u64, + ) -> anyhow::Result<()>; + + fn get_background_submit_block_cursor(&self) -> anyhow::Result>; + fn set_background_submit_block_cursor(&self, cursor: u128) -> anyhow::Result<()>; + + fn get_last_block_number(&self) -> anyhow::Result>; + + // try to fix submitting blocks by last tx order(if not None) at starting, + // only could be called after try_fix_last_block_number(which has been invoked in new) + fn catchup_submitting_blocks(&self, last_order: Option) -> anyhow::Result<()>; +} + +#[derive(Clone)] +pub struct DAMetaDBStore { + block_submit_state_store: DABlockSubmitStateStore, + block_cursor_store: DABlockCursorStore, +} + +impl DAMetaDBStore { + pub fn new(instance: raw_store::StoreInstance) -> anyhow::Result { + let store = DAMetaDBStore { + block_submit_state_store: DABlockSubmitStateStore::new(instance.clone()), + block_cursor_store: DABlockCursorStore::new(instance), + }; + store.try_fix_last_block_number()?; + Ok(store) + } + + // update last block and update submitting blocks are not in the same transaction + // so there may be a case that the submitting blocks is updated but last block is not updated + pub(crate) fn try_fix_last_block_number(&self) -> anyhow::Result<()> { + let last_block_number = self.get_last_block_number()?; + if let Some(last_block_number) = last_block_number { + let blocks = self.get_submitting_blocks(last_block_number + 1, None)?; + if let Some(block) = blocks.last() { + self.set_last_block_number(block.block_number)?; + } + } + Ok(()) + } + + pub(crate) fn set_last_block_number(&self, block_number: u128) -> anyhow::Result<()> { + self.block_cursor_store + .put_sync(LAST_BLOCK_NUMBER_KEY.to_string(), block_number) + } + + #[allow(dead_code)] + fn add_submitting_block( + &self, + block_number: u128, + tx_order_start: u64, + tx_order_end: u64, + ) -> anyhow::Result<()> { + self.block_submit_state_store.put_sync( + block_number, + BlockSubmitState::new(block_number, tx_order_start, tx_order_end), + )?; + + self.set_last_block_number(block_number)?; + Ok(()) + } + + fn add_submitting_blocks(&self, ranges: Vec) -> anyhow::Result<()> { + if ranges.is_empty() { + return Ok(()); + } + + let last_block_number = ranges.last().unwrap().block_number; + let kvs: Vec<(u128, BlockSubmitState)> = ranges + .into_iter() + .map(|range| { + ( + range.block_number, + BlockSubmitState::new( + range.block_number, + range.tx_order_start, + range.tx_order_end, + ), + ) + }) + .collect(); + let batch = CodecWriteBatch::new_puts(kvs); + self.block_submit_state_store.write_batch_sync(batch)?; + + self.set_last_block_number(last_block_number)?; + Ok(()) + } + + pub(crate) fn calc_needed_block_for_fix_submitting( + &self, + last_block_number: Option, + last_order: u64, + ) -> anyhow::Result> { + // each block has n txs, n = [1, MAX_TXS_PER_BLOCK_IN_FIX], so we need to split txs into multiple blocks + let mut blocks = Vec::new(); + let mut block_number: u128 = 0; + let mut tx_order_start: u64 = 1; // tx_order_start starts from 1 (bypass genesis_tx) + let mut tx_order_end: u64 = min(MAX_TXS_PER_BLOCK_IN_FIX as u64, last_order); + if let Some(last_block_number) = last_block_number { + let last_block_state = self + .block_submit_state_store + .kv_get(last_block_number)? + .unwrap_or_else(|| { + panic!( + "submitting block not found for existed last block: {}", + last_block_number + ) + }); + let last_range = last_block_state.block_range; + block_number = last_block_number + 1; + tx_order_start = last_range.tx_order_end + 1; + tx_order_end = min( + tx_order_start + MAX_TXS_PER_BLOCK_IN_FIX as u64 - 1, + last_order, + ); + } + while tx_order_start <= last_order { + blocks.push(BlockRange { + block_number, + tx_order_start, + tx_order_end, + }); + tx_order_start = tx_order_end + 1; + tx_order_end = min( + tx_order_start + MAX_TXS_PER_BLOCK_IN_FIX as u64 - 1, + last_order, + ); + block_number += 1; + } + Ok(blocks) + } + + // try to fix submitting blocks by last tx order(if not None) at starting, + // only could be called after try_fix_last_block_number + fn try_fix_submitting_blocks(&self, last_order: Option) -> anyhow::Result<()> { + if let Some(last_order) = last_order { + if last_order == 0 { + // only has genesis_tx + return Ok(()); + } + let last_block_number = self.get_last_block_number()?; + let ranges = + self.calc_needed_block_for_fix_submitting(last_block_number, last_order)?; + self.add_submitting_blocks(ranges)?; + } + Ok(()) + } +} + +impl DAMetaStore for DAMetaDBStore { + fn get_submitting_blocks( + &self, + start_block: u128, + exp_count: Option, + ) -> anyhow::Result> { + let exp_count = exp_count.unwrap_or(SUBMITTING_BLOCKS_PAGE_SIZE); + // try to get exp_count unsubmitted blocks + let mut blocks = Vec::with_capacity(exp_count); + let mut done_count = 0; + let mut block_number = start_block; + while done_count < exp_count { + let state = self.block_submit_state_store.kv_get(block_number)?; + if let Some(state) = state { + if !state.done { + blocks.push(BlockRange { + block_number, + tx_order_start: state.block_range.tx_order_start, + tx_order_end: state.block_range.tx_order_end, + }); + done_count += 1; + } + } else { + break; + } + block_number += 1; + } + + Ok(blocks) + } + + // TODO use rocksdb txn directly(Atomic writes across Column Families are supported), replacing of derive_store + fn append_submitting_block( + &self, + last_block_number: Option, + tx_order_start: u64, + tx_order_end: u64, + ) -> anyhow::Result { + let block_number = match last_block_number { + Some(last_block_number) => last_block_number + 1, + None => 0, + }; + + self.block_submit_state_store.put_sync( + block_number, + BlockSubmitState::new(block_number, tx_order_start, tx_order_end), + )?; + + self.set_last_block_number(block_number)?; + Ok(block_number) + } + + fn set_submitting_block_done( + &self, + block_number: u128, + tx_order_start: u64, + tx_order_end: u64, + ) -> anyhow::Result<()> { + self.block_submit_state_store.kv_put( + block_number, + BlockSubmitState::new_done(block_number, tx_order_start, tx_order_end), + ) + } + + fn get_background_submit_block_cursor(&self) -> anyhow::Result> { + self.block_cursor_store + .kv_get(BACKGROUND_SUBMIT_BLOCK_CURSOR_KEY.to_string()) + } + + fn set_background_submit_block_cursor(&self, cursor: u128) -> anyhow::Result<()> { + self.block_cursor_store + .kv_put(BACKGROUND_SUBMIT_BLOCK_CURSOR_KEY.to_string(), cursor) + } + + fn get_last_block_number(&self) -> anyhow::Result> { + self.block_cursor_store + .kv_get(LAST_BLOCK_NUMBER_KEY.to_string()) + } + + fn catchup_submitting_blocks(&self, last_order: Option) -> anyhow::Result<()> { + self.try_fix_submitting_blocks(last_order) + } +} diff --git a/crates/rooch-store/src/lib.rs b/crates/rooch-store/src/lib.rs index d52add70be..b2f6e6e590 100644 --- a/crates/rooch-store/src/lib.rs +++ b/crates/rooch-store/src/lib.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::accumulator_store::{AccumulatorStore, TransactionAccumulatorStore}; +use crate::da_store::{DAMetaDBStore, DAMetaStore}; use crate::meta_store::{MetaDBStore, MetaStore}; use crate::state_store::{StateDBStore, StateStore}; use crate::transaction_store::{TransactionDBStore, TransactionStore}; @@ -16,6 +17,7 @@ use prometheus::Registry; use raw_store::metrics::DBMetrics; use raw_store::rocks::RocksDB; use raw_store::{ColumnFamilyName, StoreInstance}; +use rooch_types::da::batch::BlockRange; use rooch_types::sequencer::SequencerInfo; use rooch_types::transaction::LedgerTransaction; use std::fmt::{Debug, Display, Formatter}; @@ -23,11 +25,13 @@ use std::path::Path; use std::sync::Arc; pub mod accumulator_store; +pub mod da_store; pub mod meta_store; pub mod state_store; +pub mod transaction_store; + #[cfg(test)] mod tests; -pub mod transaction_store; // pub const DEFAULT_COLUMN_FAMILY_NAME: ColumnFamilyName = "default"; pub const TRANSACTION_COLUMN_FAMILY_NAME: ColumnFamilyName = "transaction"; @@ -38,6 +42,9 @@ pub const TX_ACCUMULATOR_NODE_COLUMN_FAMILY_NAME: ColumnFamilyName = "transactio pub const STATE_CHANGE_SET_COLUMN_FAMILY_NAME: ColumnFamilyName = "state_change_set"; +pub const DA_BLOCK_SUBMIT_STATE_COLUMN_FAMILY_NAME: ColumnFamilyName = "da_block_submit_state"; +pub const DA_BLOCK_CURSOR_COLUMN_FAMILY_NAME: ColumnFamilyName = "da_last_block_number"; + ///db store use cf_name vec to init /// Please note that adding a column family needs to be added in vec simultaneously, remember!! static VEC_COLUMN_FAMILY_NAME: Lazy> = Lazy::new(|| { @@ -47,6 +54,8 @@ static VEC_COLUMN_FAMILY_NAME: Lazy> = Lazy::new(|| { META_SEQUENCER_INFO_COLUMN_FAMILY_NAME, TX_ACCUMULATOR_NODE_COLUMN_FAMILY_NAME, STATE_CHANGE_SET_COLUMN_FAMILY_NAME, + DA_BLOCK_SUBMIT_STATE_COLUMN_FAMILY_NAME, + DA_BLOCK_CURSOR_COLUMN_FAMILY_NAME, ] }); @@ -65,6 +74,7 @@ pub struct RoochStore { pub meta_store: MetaDBStore, pub transaction_accumulator_store: AccumulatorStore, pub state_store: StateDBStore, + pub da_meta_store: DAMetaDBStore, } impl RoochStore { @@ -82,13 +92,15 @@ impl RoochStore { } pub fn new_with_instance(instance: StoreInstance, _registry: &Registry) -> Result { + let da_meta_store = DAMetaDBStore::new(instance.clone())?; let store = Self { transaction_store: TransactionDBStore::new(instance.clone()), meta_store: MetaDBStore::new(instance.clone()), transaction_accumulator_store: AccumulatorStore::new_transaction_accumulator_store( instance.clone(), ), - state_store: StateDBStore::new(instance), + state_store: StateDBStore::new(instance.clone()), + da_meta_store, }; Ok(store) } @@ -116,6 +128,10 @@ impl RoochStore { pub fn get_state_store(&self) -> &StateDBStore { &self.state_store } + + pub fn get_da_meta_store(&self) -> &DAMetaDBStore { + &self.da_meta_store + } } impl Display for RoochStore { @@ -197,3 +213,59 @@ impl StateStore for RoochStore { self.get_state_store().remove_state_change_set(tx_order) } } + +impl DAMetaStore for RoochStore { + fn get_submitting_blocks( + &self, + start_block: u128, + exp_count: Option, + ) -> Result> { + self.get_da_meta_store() + .get_submitting_blocks(start_block, exp_count) + } + + fn append_submitting_block( + &self, + last_block_number: Option, + tx_order_start: u64, + tx_order_end: u64, + ) -> Result { + self.get_da_meta_store().append_submitting_block( + last_block_number, + tx_order_start, + tx_order_end, + ) + } + + fn set_submitting_block_done( + &self, + block_number: u128, + tx_order_start: u64, + tx_order_end: u64, + ) -> Result<()> { + self.get_da_meta_store().set_submitting_block_done( + block_number, + tx_order_start, + tx_order_end, + ) + } + + fn get_background_submit_block_cursor(&self) -> Result> { + self.get_da_meta_store() + .get_background_submit_block_cursor() + } + + fn set_background_submit_block_cursor(&self, cursor: u128) -> Result<()> { + self.get_da_meta_store() + .set_background_submit_block_cursor(cursor) + } + + fn get_last_block_number(&self) -> Result> { + self.get_da_meta_store().get_last_block_number() + } + + fn catchup_submitting_blocks(&self, last_order: Option) -> Result<()> { + self.get_da_meta_store() + .catchup_submitting_blocks(last_order) + } +} diff --git a/crates/rooch-store/src/tests/mod.rs b/crates/rooch-store/src/tests/mod.rs index cb1dbc2af8..22e4a2649a 100644 --- a/crates/rooch-store/src/tests/mod.rs +++ b/crates/rooch-store/src/tests/mod.rs @@ -2,3 +2,4 @@ // SPDX-License-Identifier: Apache-2.0 mod test_accumulator; +mod test_da_store; diff --git a/crates/rooch-store/src/tests/test_da_store.rs b/crates/rooch-store/src/tests/test_da_store.rs new file mode 100644 index 0000000000..6534fbb379 --- /dev/null +++ b/crates/rooch-store/src/tests/test_da_store.rs @@ -0,0 +1,274 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::da_store::{DAMetaStore, MAX_TXS_PER_BLOCK_IN_FIX}; +use crate::RoochStore; +use rooch_types::da::batch::BlockRange; + +#[tokio::test] +async fn test_append_submitting_blocks() { + let (rooch_store, _) = RoochStore::mock_rooch_store().unwrap(); + let da_meta_store = rooch_store.get_da_meta_store(); + + da_meta_store.append_submitting_block(None, 1, 6).unwrap(); + + let last_block_number = 0; + let tx_order_start = 7; + let tx_order_end = 7; + da_meta_store + .append_submitting_block(Some(last_block_number), tx_order_start, tx_order_end) + .unwrap(); + + let submitting_blocks = da_meta_store.get_submitting_blocks(0, None).unwrap(); + assert_eq!(submitting_blocks.len(), 2); + assert_eq!(submitting_blocks[0].block_number, 0); + assert_eq!(submitting_blocks[0].tx_order_start, 1); + assert_eq!(submitting_blocks[0].tx_order_end, 6); + assert_eq!(submitting_blocks[1].block_number, 1); + assert_eq!(submitting_blocks[1].tx_order_start, 7); + assert_eq!(submitting_blocks[1].tx_order_end, 7); + + let submitting_blocks = da_meta_store.get_submitting_blocks(0, Some(2)).unwrap(); + assert_eq!(submitting_blocks.len(), 2); + assert_eq!(submitting_blocks[0].block_number, 0); + assert_eq!(submitting_blocks[0].tx_order_start, 1); + assert_eq!(submitting_blocks[0].tx_order_end, 6); + assert_eq!(submitting_blocks[1].block_number, 1); + assert_eq!(submitting_blocks[1].tx_order_start, 7); + assert_eq!(submitting_blocks[1].tx_order_end, 7); + + let submitting_blocks = da_meta_store.get_submitting_blocks(1, None).unwrap(); + assert_eq!(submitting_blocks.len(), 1); + assert_eq!(submitting_blocks[0].block_number, 1); + assert_eq!(submitting_blocks[0].tx_order_start, 7); + assert_eq!(submitting_blocks[0].tx_order_end, 7); + + let submitting_blocks = da_meta_store.get_submitting_blocks(1, Some(1)).unwrap(); + assert_eq!(submitting_blocks.len(), 1); + assert_eq!(submitting_blocks[0].block_number, 1); + assert_eq!(submitting_blocks[0].tx_order_start, 7); + assert_eq!(submitting_blocks[0].tx_order_end, 7); +} + +#[tokio::test] +async fn test_try_fix_last_block_number() { + let (rooch_store, _) = RoochStore::mock_rooch_store().unwrap(); + let da_meta_store = rooch_store.get_da_meta_store(); + + let tx_order_start = 7; + let tx_order_end = 7; + let last_block_number = da_meta_store + .append_submitting_block(None, tx_order_start, tx_order_end) + .unwrap(); + da_meta_store + .append_submitting_block(Some(last_block_number), tx_order_start, tx_order_end) + .unwrap(); + da_meta_store.set_last_block_number(0).unwrap(); + assert_eq!(da_meta_store.get_last_block_number().unwrap().unwrap(), 0); + let submitting_blocks = da_meta_store.get_submitting_blocks(0, None).unwrap(); + assert_eq!(submitting_blocks.len(), 2); + assert_eq!(submitting_blocks[1].block_number, 1); + assert_eq!(submitting_blocks[1].tx_order_start, 7); + assert_eq!(submitting_blocks[1].tx_order_end, 7); + da_meta_store.try_fix_last_block_number().unwrap(); + assert_eq!(da_meta_store.get_last_block_number().unwrap().unwrap(), 1); +} + +#[tokio::test] +async fn test_calc_needed_block_for_fix_submitting() { + let (rooch_store, _) = RoochStore::mock_rooch_store().unwrap(); + + test_calc_need_submitting_case(0, None, 0, rooch_store.clone(), None); + test_calc_need_submitting_case(1, None, 1, rooch_store.clone(), Some(0)); + test_calc_need_submitting_case(2, None, 10, rooch_store.clone(), Some(0)); + test_calc_need_submitting_case( + 3, + None, + MAX_TXS_PER_BLOCK_IN_FIX as u64, + rooch_store.clone(), + Some(0), + ); + test_calc_need_submitting_case( + 4, + None, + MAX_TXS_PER_BLOCK_IN_FIX as u64 + 1, + rooch_store.clone(), + Some(0), + ); + test_calc_need_submitting_case( + 5, + None, + MAX_TXS_PER_BLOCK_IN_FIX as u64 + 2, + rooch_store.clone(), + Some(0), + ); + test_calc_need_submitting_case( + 6, + None, + 9 + 2 * MAX_TXS_PER_BLOCK_IN_FIX as u64, + rooch_store.clone(), + Some(0), + ); + + let tx_order_end = 3 * MAX_TXS_PER_BLOCK_IN_FIX as u64 + 1; + let last_block_number = rooch_store.append_submitting_block(None, 1, 3).unwrap(); + let last_block_number = rooch_store + .append_submitting_block(Some(last_block_number), 4, tx_order_end) + .unwrap(); + test_calc_need_submitting_case( + 7, + Some(last_block_number), + tx_order_end, + rooch_store.clone(), + None, + ); + for i in 1..2 * MAX_TXS_PER_BLOCK_IN_FIX + 2 { + test_calc_need_submitting_case( + (7 + i) as u64, + Some(last_block_number), + tx_order_end + i as u64, + rooch_store.clone(), + Some(last_block_number + 1), + ); + } +} + +fn test_calc_need_submitting_case( + test_case: u64, + last_block_number: Option, + last_order: u64, + rooch_store: RoochStore, + exp_first_block_number: Option, +) { + let da_meta_store = rooch_store.get_da_meta_store(); + + let block_ranges = da_meta_store + .calc_needed_block_for_fix_submitting(last_block_number, last_order) + .unwrap(); + + let origin_tx_order_end = if let Some(last_block_number) = last_block_number { + let submitting_blocks = da_meta_store + .get_submitting_blocks(last_block_number, None) + .unwrap(); + Some(submitting_blocks.first().unwrap().tx_order_end) + } else { + None + }; + + check_block_ranges( + test_case, + block_ranges, + exp_first_block_number, + last_order, + origin_tx_order_end, + ); +} + +fn check_block_ranges( + test_case: u64, + block_ranges: Vec, + exp_first_block_number: Option, + last_order: u64, + origin_tx_order_end: Option, +) { + if exp_first_block_number.is_none() { + assert_eq!( + block_ranges.len(), + 0, + "Test case {}: expected no block ranges, but got {:#?}", + test_case, + block_ranges, + ); + return; + } + assert!( + !block_ranges.is_empty(), + "Test case {}: expected some block ranges, but got none", + test_case, + ); + + let exp_first_block_number = exp_first_block_number.unwrap(); + let act_first_block_number = block_ranges.first().unwrap().block_number; + assert_eq!( + act_first_block_number, exp_first_block_number, + "Test case {}: first block number mismatch, expected {}, got {}", + test_case, exp_first_block_number, act_first_block_number, + ); + + let tx_start = block_ranges.first().unwrap().tx_order_start; + assert!( + tx_start > 0, + "Test case {}: first order mismatch, expected > 0, got {}", + test_case, + tx_start, + ); + + let tx_end = block_ranges.last().unwrap().tx_order_end; + assert_eq!( + tx_end, last_order, + "Test case {}: last order mismatch, expected {}, got {}", + test_case, last_order, tx_end, + ); + + for block_range in &block_ranges { + let txs = block_range.tx_order_end - block_range.tx_order_start + 1; + assert!( + txs <= MAX_TXS_PER_BLOCK_IN_FIX as u64, + "Test case {}: too many txs in block range {:#?}, max allowed {}", + test_case, + block_range, + MAX_TXS_PER_BLOCK_IN_FIX + ); + assert!( + block_range.tx_order_start <= block_range.tx_order_end, + "Test case {}: tx_order_start > tx_order_end in block range {:#?}", + test_case, + block_range, + ); + } + + for i in 0..block_ranges.len() - 1 { + let tx_order_end = block_ranges[i].tx_order_end; + let tx_order_start = block_ranges[i + 1].tx_order_start; + assert_eq!( + tx_order_end + 1, + tx_order_start, + "Test case {}: tx_order continuity issue between blocks {:#?} and {:#?}", + test_case, + block_ranges[i], + block_ranges[i + 1] + ); + + let block_number = block_ranges[i].block_number; + let next_block_number = block_ranges[i + 1].block_number; + assert_eq!( + block_number + 1, + next_block_number, + "Test case {}: block number continuity issue between blocks {:#?} and {:#?}", + test_case, + block_ranges[i], + block_ranges[i + 1] + ); + } + + let total_txs: u64 = block_ranges + .iter() + .map(|block_range| block_range.tx_order_end - block_range.tx_order_start + 1) + .sum(); + let exp_txs = if let Some(origin_tx_order_end) = origin_tx_order_end { + last_order - origin_tx_order_end + } else { + last_order + }; + assert_eq!( + exp_txs, + total_txs, + "Test case {}: total txs in new blocks mismatch, expected {}, got {}. last order: {}; origin tx order end: {:?}. block ranges: {:#?}", + test_case, + exp_txs, + total_txs, + last_order, + origin_tx_order_end, + block_ranges, + ); +} diff --git a/crates/rooch-types/Cargo.toml b/crates/rooch-types/Cargo.toml index 3d8e6a266e..eca447d429 100644 --- a/crates/rooch-types/Cargo.toml +++ b/crates/rooch-types/Cargo.toml @@ -41,6 +41,8 @@ bs58 = { workspace = true, features = ["check"] } chacha20poly1305 = { workspace = true } argon2 = { workspace = true } tracing = { workspace = true } +xxhash-rust = { workspace = true, features = ["xxh3"] } +lz4 = { workspace = true } move-core-types = { workspace = true } move-vm-types = { workspace = true } diff --git a/crates/rooch-types/src/da/batch.rs b/crates/rooch-types/src/da/batch.rs new file mode 100644 index 0000000000..a3d091afd5 --- /dev/null +++ b/crates/rooch-types/src/da/batch.rs @@ -0,0 +1,125 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use crate::crypto::{RoochKeyPair, Signature}; +use crate::transaction::LedgerTransaction; +use moveos_types::h256::{sha2_256_of, H256}; +use serde::{Deserialize, Serialize}; + +#[derive(Eq, PartialEq, Hash, Deserialize, Serialize, Clone, Debug)] +/// The tx order range of the block. +pub struct BlockRange { + /// The Rooch block number for DA, each batch maps to a block + pub block_number: u128, + /// The start tx order of the block (inclusive) + pub tx_order_start: u64, + /// The end tx order of the block (inclusive) + pub tx_order_end: u64, +} + +#[derive(Eq, PartialEq, Hash, Deserialize, Serialize, Clone, Debug)] +/// The state of the block submission. +pub struct BlockSubmitState { + /// tx order range of the block + pub block_range: BlockRange, + /// submitted or not + pub done: bool, +} + +impl BlockSubmitState { + /// Create a new BlockSubmitState + pub fn new(block_number: u128, tx_order_start: u64, tx_order_end: u64) -> Self { + Self { + block_range: BlockRange { + block_number, + tx_order_start, + tx_order_end, + }, + done: false, + } + } + pub fn new_done(block_number: u128, tx_order_start: u64, tx_order_end: u64) -> Self { + Self { + block_range: BlockRange { + block_number, + tx_order_start, + tx_order_end, + }, + done: true, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +/// Meta of DA batch +pub struct DABatchMeta { + /// tx order range of the block + pub block_range: BlockRange, + /// sha256h of encoded tx_list + pub tx_list_hash: H256, +} + +impl DABatchMeta { + pub fn new( + block_number: u128, + tx_order_start: u64, + tx_order_end: u64, + tx_list_hash: H256, + ) -> Self { + Self { + block_range: BlockRange { + block_number, + tx_order_start, + tx_order_end, + }, + tx_list_hash, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub struct SignedDABatchMeta { + pub meta: DABatchMeta, + pub signature: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +/// A batch is a collection of transactions. It is the unit of data flow in DA Stream +pub struct DABatch { + /// The metadata of the batch + pub meta: DABatchMeta, + /// meta signature, signed by sequencer. + pub meta_signature: Vec, + /// encoded Vec + pub tx_list_bytes: Vec, +} + +impl DABatch { + pub fn new( + block_number: u128, + tx_order_start: u64, + tx_order_end: u64, + tx_list: &Vec, + sequencer_key: RoochKeyPair, + ) -> Self { + let tx_list_bytes = bcs::to_bytes(tx_list).expect("encode tx_list should success"); + let tx_list_hash = sha2_256_of(&tx_list_bytes); + let batch_meta = DABatchMeta::new(block_number, tx_order_start, tx_order_end, tx_list_hash); + let meta_bytes = bcs::to_bytes(&batch_meta).expect("encode batch_meta should success"); + let meta_hash = sha2_256_of(&meta_bytes); + let meta_signature = Signature::sign(&meta_hash.0, &sequencer_key) + .as_ref() + .to_vec(); + + Self { + meta: batch_meta, + meta_signature, + tx_list_bytes, + } + } + + pub fn get_hash(&self) -> H256 { + let meta_bytes = bcs::to_bytes(&self.meta).expect("encode batch_meta should success"); + sha2_256_of(&meta_bytes) + } +} diff --git a/crates/rooch-da/src/chunk.rs b/crates/rooch-types/src/da/chunk.rs similarity index 77% rename from crates/rooch-da/src/chunk.rs rename to crates/rooch-types/src/da/chunk.rs index 3f5789d113..f73873e219 100644 --- a/crates/rooch-da/src/chunk.rs +++ b/crates/rooch-types/src/da/chunk.rs @@ -1,8 +1,8 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -use crate::messages::Batch; -use crate::segment::{Segment, SegmentID, SegmentV0}; +use crate::da::batch::DABatch; +use crate::da::segment::{Segment, SegmentID, SegmentV0}; use lz4::EncoderBuilder; use serde::{Deserialize, Serialize}; use std::io; @@ -36,30 +36,24 @@ pub trait Chunk { fn to_bytes(&self) -> Vec; fn get_version(&self) -> ChunkVersion; fn to_segments(&self, max_segment_size: usize) -> Vec>; - fn get_batch(&self) -> Batch; + fn get_batches(&self) -> Vec; + fn get_chunk_id(&self) -> u128; } // ChunkV0: -// 1. each chunk maps to a batch +// 1. each chunk maps to a batch (block number is chunk_id) // 2. batch_data compressed by lz4 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct ChunkV0 { pub version: ChunkVersion, - pub batch: Batch, + pub batch: DABatch, } -impl From for ChunkV0 { - fn from(batch: Batch) -> Self { +impl From for ChunkV0 { + fn from(batch: DABatch) -> Self { Self { version: ChunkVersion::V0, - batch: Batch { - block_number: batch.block_number, - tx_count: batch.tx_count, - prev_tx_accumulator_root: batch.prev_tx_accumulator_root, - tx_accumulator_root: batch.tx_accumulator_root, - batch_hash: batch.batch_hash, - data: batch.data, - }, + batch, } } } @@ -87,7 +81,7 @@ impl Chunk for ChunkV0 { let segments_data = bytes.chunks(max_segment_size); let segments_count = segments_data.len(); - let chunk_id = self.batch.block_number; + let chunk_id = self.get_chunk_id(); segments_data .enumerate() .map(|(i, data)| { @@ -107,8 +101,13 @@ impl Chunk for ChunkV0 { .collect::>() } - fn get_batch(&self) -> Batch { - self.batch.clone() + fn get_batches(&self) -> Vec { + vec![self.batch.clone()] + } + + /// using batch.meta.block_number as chunk_id + fn get_chunk_id(&self) -> u128 { + self.batch.meta.block_range.block_number } } @@ -175,29 +174,30 @@ impl ChunkV0 { #[cfg(test)] mod tests { use super::*; - use moveos_types::h256; + use crate::crypto::RoochKeyPair; + use crate::test_utils::random_ledger_transaction; + use crate::transaction::LedgerTransaction; #[test] fn test_chunk_v0() { - let batch = Batch { - block_number: 1, - tx_count: 1, - prev_tx_accumulator_root: Default::default(), - tx_accumulator_root: Default::default(), - batch_hash: h256::sha2_256_of(&[1, 2, 3, 4, 5]), - data: vec![1, 2, 3, 4, 5], - }; + let tx_cnt = 128; + let keypair = RoochKeyPair::generate_secp256k1(); + + let tx_list = (0..tx_cnt) + .map(|_| random_ledger_transaction()) + .collect::>(); + let batch = DABatch::new(123, 56, 78, &tx_list, keypair); let chunk = ChunkV0::from(batch.clone()); - let segments = chunk.to_segments(3); - assert_eq!(segments.len(), 39); + let segments = chunk.to_segments(1023); let chunk = chunk_from_segments(segments).unwrap(); - assert_eq!(chunk.get_batch(), batch); + let batches = chunk.get_batches(); + let act_batch = batches.first().unwrap(); + assert_eq!(act_batch, &batch); - assert_eq!( - chunk.get_batch().batch_hash, - h256::sha2_256_of(&[1, 2, 3, 4, 5]) - ); + let act_tx_list: Vec = + bcs::from_bytes(&act_batch.tx_list_bytes).expect("decode tx_list should success"); + assert_eq!(tx_list, act_tx_list); } } diff --git a/crates/rooch-da/src/server/celestia/actor/mod.rs b/crates/rooch-types/src/da/mod.rs similarity index 59% rename from crates/rooch-da/src/server/celestia/actor/mod.rs rename to crates/rooch-types/src/da/mod.rs index 83afd4d573..ee7e48696d 100644 --- a/crates/rooch-da/src/server/celestia/actor/mod.rs +++ b/crates/rooch-types/src/da/mod.rs @@ -1,4 +1,6 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -pub mod server; +pub mod batch; +pub mod chunk; +pub mod segment; diff --git a/crates/rooch-da/src/segment.rs b/crates/rooch-types/src/da/segment.rs similarity index 99% rename from crates/rooch-da/src/segment.rs rename to crates/rooch-types/src/da/segment.rs index 61cd75a285..d570a2bab6 100644 --- a/crates/rooch-da/src/segment.rs +++ b/crates/rooch-types/src/da/segment.rs @@ -1,7 +1,7 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -use crate::chunk::ChunkVersion; +use crate::da::chunk::ChunkVersion; use serde::Serialize; use std::fmt; use std::str::FromStr; diff --git a/crates/rooch-types/src/lib.rs b/crates/rooch-types/src/lib.rs index b1dce6f5af..6612bd4aeb 100644 --- a/crates/rooch-types/src/lib.rs +++ b/crates/rooch-types/src/lib.rs @@ -8,6 +8,7 @@ pub mod bitcoin; pub mod block; pub mod coin_type; pub mod crypto; +pub mod da; pub mod error; pub mod framework; pub mod function_arg; diff --git a/crates/rooch/src/commands/account/commands/list.rs b/crates/rooch/src/commands/account/commands/list.rs index c3703b5c73..fcbf7bdc0c 100644 --- a/crates/rooch/src/commands/account/commands/list.rs +++ b/crates/rooch/src/commands/account/commands/list.rs @@ -98,7 +98,7 @@ impl CommandAction> for ListCommand { .collect(); if self.json { - let mut accounts_view: AccountsView = HashMap::new(); + let mut accounts_view: AccountsView = HashMap::with_capacity(account_views.len()); let mut i = 0; for account in account_views { if account.active { diff --git a/crates/rooch/src/commands/move_cli/commands/run_function.rs b/crates/rooch/src/commands/move_cli/commands/run_function.rs index a765e7ffdb..1c022d13df 100644 --- a/crates/rooch/src/commands/move_cli/commands/run_function.rs +++ b/crates/rooch/src/commands/move_cli/commands/run_function.rs @@ -9,8 +9,6 @@ use clap::Parser; use move_command_line_common::types::ParsedStructType; use move_core_types::language_storage::TypeTag; use moveos_types::transaction::MoveAction; -use rooch_key::key_derive::verify_password; -use rooch_key::keystore::account_keystore::AccountKeystore; use rooch_rpc_api::jsonrpc_types::{ ExecuteTransactionResponseView, HumanReadableDisplay, KeptVMStatusView, }; @@ -21,7 +19,6 @@ use rooch_types::{ function_arg::ParsedFunctionId, transaction::rooch::RoochTransaction, }; -use rpassword::prompt_password; /// Run a Move function #[derive(Parser)] @@ -72,7 +69,7 @@ pub struct RunFunction { #[async_trait] impl CommandAction for RunFunction { async fn execute(self) -> RoochResult { - let context = self.context.build()?; + let context = self.context.build_require_password()?; let address_mapping = context.address_mapping(); let sender: RoochAddress = context.resolve_address(self.tx_options.sender)?.into(); let max_gas_amount: Option = self.tx_options.max_gas_amount; @@ -121,35 +118,9 @@ impl CommandAction for RunFunction { let tx_data = context .build_tx_data(sender, action, max_gas_amount) .await?; - let tx = if context.keystore.get_if_password_is_empty() { - context - .keystore - .sign_transaction_via_session_key(&sender, tx_data, &session_key, None) - .map_err(|e| RoochError::SignMessageError(e.to_string()))? - } else { - let password = - prompt_password("Enter the password to run functions:").unwrap_or_default(); - let is_verified = verify_password( - Some(password.clone()), - context.keystore.get_password_hash(), - )?; - - if !is_verified { - return Err(RoochError::InvalidPasswordError( - "Password is invalid".to_owned(), - )); - } - - context - .keystore - .sign_transaction_via_session_key( - &sender, - tx_data, - &session_key, - Some(password), - ) - .map_err(|e| RoochError::SignMessageError(e.to_string()))? - }; + let tx = context + .sign_transaction_via_session_key(&sender, tx_data, &session_key) + .map_err(|e| RoochError::SignMessageError(e.to_string()))?; context.execute(tx).await? } (None, None) => { diff --git a/crates/rooch/src/commands/statedb/commands/mod.rs b/crates/rooch/src/commands/statedb/commands/mod.rs index f7ccd9f08a..2a6ff9d7f2 100644 --- a/crates/rooch/src/commands/statedb/commands/mod.rs +++ b/crates/rooch/src/commands/statedb/commands/mod.rs @@ -544,7 +544,7 @@ mod tests { // all outpoints are unique fn random_outpoints(n: usize) -> Vec { - let mut outpoints = HashSet::new(); + let mut outpoints = HashSet::with_capacity(n); while outpoints.len() < n { outpoints.insert(random_outpoint()); } @@ -553,7 +553,7 @@ mod tests { // all inscriptions are unique fn random_inscriptions(n: usize) -> Vec { - let mut inscriptions = HashSet::new(); + let mut inscriptions = HashSet::with_capacity(n); while inscriptions.len() < n { inscriptions.insert(random_inscription_id()); } diff --git a/docs/website/pages/blog/hacker-house-1th.en-US.mdx b/docs/website/pages/blog/hacker-house-1th.en-US.mdx new file mode 100644 index 0000000000..ce9b36b700 --- /dev/null +++ b/docs/website/pages/blog/hacker-house-1th.en-US.mdx @@ -0,0 +1,88 @@ +--- +title: 'Join the Babylon Hacker House 2024 with Rooch Network: Building Native Bitcoin Applications on the Rooch & Babylon Ecosystem' +author: omnihand +category: Campaign +date: 2024/10/11 +description: '' +image: '/blog/hacker-house.jpg' +--- + +import PostHeader from '/components/blog/postHeader' + + + +![](/blog/hacker-house.jpg) + +Babylon, the leading native Bitcoin staking and timestamping protocol, is hosting its first Hacker House in Bangkok from November 5 to November 9, 2024, just ahead of DevCon 24. This event will focus on native Bitcoin staking, DeFi, and economic security, coinciding with the cap 2 of Babylon Bitcoin staking mainnet Phase-1 launch. + +As a key ecosystem partner of Babylon, Rooch Network is committed to jointly empowering the Bitcoin ecosystem. Together, we are pioneering native Bitcoin applications and yield opportunities for Bitcoin. With its pre-mainnet launching soon, Rooch Network will enhance the utility and yield potential for Bitcoin staked on Babylon, offering diverse Bitcoin-native application scenarios across the entire Bitcoin ecosystem. Proud to sponsor Babylon Hacker House 2024, Rooch Network is excited to invite developers to join us at this transformative event, exploring ways to build innovative solutions on the Rooch & Babylon ecosystem. + +If you missed Babylon Hacker House's general registration deadline of October 6, 2024, you’re in luck! **Rooch Network has exclusive slots available for two teams interested in participating. By joining through Rooch, you’ll receive resources and support from both Babylon and Rooch Network, with the added benefit that your demo projects will be directly listed on Rooch’s Grow Bitcoin Launchpad.** + +**To qualify, your demo project should be built on Rooch Network and meet the Hacker House’s requirements, contributing innovative solutions that integrate with both Babylon and Rooch.** + +## What to Expect at the Hacker House + +The five-day event follows an online pre-hack phase from October 29 to November 2, leading into an immersive, in-person experience: + +- In person event TL;DR: +- Date: November 5-9, 2024 +- Location: Samyan Mitrtown, Bangkok, Thailand +- Participants: 70 selected hackers +- Focus Areas: Native Bitcoin staking, DeFi, and Blockchain Economic security + +### What’s in Store? + +#### Part I: Benefits for All Participants + +- 💻 Hands-on workshops +- 👩‍💻 On-site 1:1 support +- 🤝 Collaborate with the Babylon dev team +- 🍻 Access to private receptions and dinners +- 💵 $800 travel allowance for accommodation and meals +- 🏆 Opportunity to win from a $20,000 prize pool +- 📄 Eligibility for an $80,000 grant pool +- 💼 Demo your project to VC partners + +#### Part II: Exclusive Rooch Network Benefits + +- 💰 Eligible for a $10,000 grant pool (in ROOCH token) +- 🚀 Listing on Grow Bitcoin Launchpad +- 💻 Rooch Network hands-on workshops +- 👩‍💻 1:1 support from Rooch’s dev team +- 🔑 Opportunity to join the Rooch Network team + +### A Hub for BTC Innovation + +The event's structure is designed in two parts to maximize learning and development opportunities: + +#### Online Pre-Hack (October 29 - November 2): + +Where team formation, brainstorming, mentor office hours, and online workshops happen a week ahead of the Hacker House. + +#### In-Person Hacker House (November 5-9): + +A high level agenda: + +- Day 1: Welcome and icebreakers +- Day 2: BTC Day - Intro to BTC Staking, Wallet & dApp Integrations +- Day 3: PoS Day - PoS Integrations Workshop (CosmosSDK) +- Day 4: Economy Day - Restaking, Tokenomics Design, Economic Engineering +- Day 5: Demo Day & Award Ceremony + +## Why Participate? + +- Learn from blockchain industry leaders +- Network with other developers and founders +- Gain hands-on experience with state-of-the-art blockchain technology +- Secure potential funding or grants for your project +- Help shape the future of Bitcoin staking and DeFi +- Take part in Rooch Network’s project acceleration program + +Bitcoin innovation is on the rise. During Babylon’s recent mainnet phase, the strong demand for native BTC staking was evident. As the native application layer for the Bitcoin ecosystem, Rooch Network aims to enhance the utility of Babylon-staked BTC, delivering more Bitcoin-native applications for users. The Babylon Hacker House offers a unique chance to contribute to the future of Bitcoin within the joint Babylon & Rooch ecosystem. + +Ready to innovate, learn, and grow with us? [**Apply here now! The deadline for applications through Rooch Network is October 19, 2024.**](https://forms.gle/w7cNaqJhMZBdD7Yc7) + +## About Rooch + +Rooch Network is a MoveVM-based application layer on Bitcoin, empowering the Babylon ecosystem with the Move developer community and native Bitcoin applications. Rooch Network aims to enable yields and utilities for all BTC users and stakers by working closely with the Babylon ecosystem. diff --git a/docs/website/pages/blog/hacker-house-1th.zh-CN.mdx b/docs/website/pages/blog/hacker-house-1th.zh-CN.mdx new file mode 100644 index 0000000000..58d2d67342 --- /dev/null +++ b/docs/website/pages/blog/hacker-house-1th.zh-CN.mdx @@ -0,0 +1,88 @@ +--- +title: '与 Rooch Network 一起加入 Babylon Hacker House 2024:在 Rooch & Babylon 生态系统上构建原生比特币应用程序' +author: omnihand +category: Campaign +date: 2024/10/11 +description: '' +image: '/blog/hacker-house.jpg' +--- + +import PostHeader from '/components/blog/postHeader' + + + +![](/blog/hacker-house.jpg) + +Babylon 是领先的原生比特币质押和时间戳协议,将于 2024 年 11 月 5 日至 9 日在曼谷举办其首个 Hacker House,就在 DevCon 24 之前。该活动将重点关注原生比特币质押、DeFi 和经济安全,同时随着巴比伦比特币质押主网第一阶段启动的 cap 2。 + +作为 Babylon 的重要生态合作伙伴,Rooch Network 致力于共同赋能比特币生态。我们共同开创比特币原生应用并为比特币创造机会。随着预主网的推出,Rooch Network 将增强 Babylon 上质押的比特币的效用和收益潜力,在整个比特币生态系统中提供多样化的比特币原生应用场景。Rooch Network 很荣幸能够赞助 2024 年 Babylon Hacker House,并很高兴邀请开发者加入我们这一变革性活动,探索在 Rooch & Babylon 生态系统上构建创新解决方案的方法。 + +如果您错过了 Babylon Hacker House 的一般注册截止日期 2024 年 10 月 6 日,那么您很幸运!**Rooch Network 为有兴趣参与的两支团队提供了独家席位。通过 Rooch 加入,您将获得来自 Babylon 和 Rooch Network 的资源和支持,还有一个额外的好处,您的演示项目将直接列在 Rooch 的 Grow Bitcoin Launchpad 上。** + +**为了获得资格,您的演示项目应该建立在 Rooch Network 上并满足 Hacker House 的要求,贡献与 Babylon 和 Rooch 集成的创新解决方案。** + +## 在黑客之家可以期待什么 + +为期五天的活动紧随 10 月 29 日至 11 月 2 日的在线预黑客阶段之后,带来身临其境的现场体验: + +- 亲自参加活动 TL;DR: +- 日期:2024年11月5-9日 +- 地点:Samyan Mitrtown,曼谷,泰国 +- 参与者:70名选定的黑客 +- 重点领域:原生比特币质押、DeFi 和区块链经济安全 + +### Store 里有什么? + +#### 第一部分:所有参与者的好处 + +- 💻 实践研讨会 +- 👩‍💻现场1:1支持 +- 🤝 与 Babylon 开发团队合作 +- 🍻 参加私人招待会和晚宴 +- 💵 $800 住宿和膳食旅行津贴 +- 🏆 有机会赢得 20,000 美元奖池 +- 📄 获得 80,000 美元补助池的资格 +- 💼 向 VC 合作伙伴演示您的项目 + +#### 第二部分:Rooch Network 的独家优势 + +- 💰 有资格获得 10,000 美元的资助池(ROOCH 代币) +- 🚀 在 Grow Bitcoin Launchpad 上列出 +- 💻 Rooch Network 实践研讨会 +- 👩‍💻 Rooch 开发团队的 1:1 支持 +- 🔑 有机会加入 Rooch Network 团队 + +### 比特币创新中心 + +该活动的结构分为两部分,以最大限度地增加学习和发展机会: + +#### 在线预黑客活动(10 月 29 日至 11 月 2 日): + +团队组建、头脑风暴、导师办公时间和在线研讨会在黑客之家举行前一周举行。 + +#### 面对面黑客之家(11 月 5 日至 9 日): + +高级别议程: + +- 第 1 天:欢迎和破冰活动 +- 第 2 天:BTC Day - BTC 质押、钱包和 dApp 集成介绍 +- 第 3 天:PoS 日 - PoS 集成研讨会 (CosmosSDK) +- 第 4 天:经济日 - 重新抵押、代币经济学设计、经济工程 +- 第 5 天:演示日和颁奖典礼 + +## 为什么参加? + +- 向区块链行业领袖学习 +- 与其他开发者和创始人建立联系 +- 获得最先进的区块链技术的实践经验 +- 为您的项目确保潜在的资金或赠款 +- 帮助塑造比特币质押和 DeFi 的未来 +- 参与 Rooch Network 的项目加速计划 + +比特币创新正在兴起。在 Babylon 最近的主网阶段,对原生 BTC 质押的强劲需求是显而易见的。作为比特币生态系统的原生应用层,Rooch Network 旨在增强 Babylon 质押 BTC 的效用,为用户提供更多比特币原生应用。 Babylon Hacker House 提供了一个独特的机会,可以在 Babylon & Rooch 联合生态系统中为比特币的未来做出贡献。 + +准备好与我们一起创新、学习和成长了吗?[**现在就在这里申请吧!通过 Rooch Network 申请的截止日期是 2024 年 10 月 19 日。**](https://forms.gle/w7cNaqJhMZBdD7Yc7) + +## 关于 Rooch + +Rooch Network 是比特币上基于 MoveVM 的应用程序层,通过 Move 开发者社区和本机比特币应用程序为 Babylon 生态系统提供支持。Rooch Network 旨在通过与 Babylon 生态系统密切合作,为所有 BTC 用户和质押者提供收益和实用性。 diff --git a/docs/website/pages/learn/core-concepts/_meta.en-US.json b/docs/website/pages/learn/core-concepts/_meta.en-US.json index fb8e7cdf6b..279e4b5c2a 100644 --- a/docs/website/pages/learn/core-concepts/_meta.en-US.json +++ b/docs/website/pages/learn/core-concepts/_meta.en-US.json @@ -3,9 +3,7 @@ "accounts": "Account", "transaction": "Transaction", "objects": "Object", - "move-contracts": "Move concepts", - "token": { - "title": "Token", - "display": "hidden" - } + "coins": "Coin", + "rgas": "RGas", + "move-contracts": "Move concepts" } diff --git a/docs/website/pages/learn/core-concepts/_meta.zh-CN.json b/docs/website/pages/learn/core-concepts/_meta.zh-CN.json index 46a0fa1505..d7d4dbdff8 100644 --- a/docs/website/pages/learn/core-concepts/_meta.zh-CN.json +++ b/docs/website/pages/learn/core-concepts/_meta.zh-CN.json @@ -3,9 +3,7 @@ "accounts": "账户", "transaction": "交易", "objects": "对象", - "move-contracts": "Move 概念", - "token": { - "title": "Token", - "display": "hidden" - } + "coins": "代币", + "rgas": "RGas", + "move-contracts": "Move 概念" } diff --git a/docs/website/pages/learn/core-concepts/coins.en-US.mdx b/docs/website/pages/learn/core-concepts/coins.en-US.mdx new file mode 100644 index 0000000000..f8244fb6a3 --- /dev/null +++ b/docs/website/pages/learn/core-concepts/coins.en-US.mdx @@ -0,0 +1,65 @@ +# Coin and Fungible Token + +import { Callout, FileTree } from 'nextra/components' + +In Rooch, `Coin` is a concrete implementation of `Fungible Token`. It is included in the [`coin` module](https://github.com/rooch-network/rooch/blob/main/frameworks/rooch-framework/sources/coin.move) of the RoochFramework. + +## Coin Type + +```move +struct Coin { + value: u256, +} +``` + +`Coin` is a generic type that contains a `value` field representing the value of the `Coin`. The type parameter `CoinType` of `Coin` represents the type of the `Coin`. In Rooch, the unique identifier for an asset type is `CoinType`, not the contract address, which is different from the ERC20 standard. + +For example, the type of Gas Coin in Rooch is `0x3::gas_coin::RGas`. Here, `0x3` is the contract address of RoochFramework, `gas_coin` is the module name, and `RGas` is the type name. These three together form a unique type identifier. + +## Registering Coin Type + +First, developers need to define a custom `CoinType`, then use the `coin::register_extend` function to create a `CoinInfo` object. The `CoinInfo` object stores relevant information about the `Coin` type, such as name, symbol, icon, decimals, etc. It also represents the management authority of the `Coin`. + +```move + #[private_generics(CoinType)] + public fun register_extend( + name: string::String, + symbol: string::String, + icon_url: Option, + decimals: u8, + ): Object> +``` + +Note that this function is protected by [`private_generics`](/build/rooch-framework/private-generics) and can only be called within the `CoinType` module. + +## CoinStore + +The `Coin` type doesn't have any `ability`, so it can't be stored directly in structures. It needs to be stored through `CoinStore`. By default, the system creates a `CoinStore` for each address of each `CoinType`. Developers can also use the `coin::create_coin_store` function to create `Object>`. `CoinStore` objects can be stored in any structure. + +```move + public fun create_coin_store(): Object> +``` + +## Private Coin and Public Coin + +In Rooch, if `CoinType` doesn't have the `store` ability, then the `Coin` is a `Private Coin`, otherwise it's a `Public Coin`. + +* `Private Coin` can only be transferred within the `CoinType` module and cannot be transferred outside the module. +* `Public Coin` can be transferred by any module. Users can directly call the `transfer::transfer_coin` function to transfer `Public Coin`. + +If developers need to customize the transfer logic of `Coin`, they can implement it by calling the `coin::transfer_extend` function within their own module. + +Note that all functions with the `extend` keyword in `coin` and `coin_store` are protected by [`private_generics`](/build/rooch-framework/private-generics), indicating that these functions are for `CoinType` module developers to extend. + + +This section is still being improved! More explanations about Coin methods need to be added: + +* `mint` and `burn` methods. +* `coin_store` related methods. +* `account_coin_store` related methods. + + +## Coins Examples + +* [private_coin](https://github.com/rooch-network/rooch/blob/main/examples/coins/sources/private_coin.move) +* [fixed_supply_coin](https://github.com/rooch-network/rooch/ diff --git a/docs/website/pages/learn/core-concepts/coins.zh-CN.mdx b/docs/website/pages/learn/core-concepts/coins.zh-CN.mdx new file mode 100644 index 0000000000..b472bb2b15 --- /dev/null +++ b/docs/website/pages/learn/core-concepts/coins.zh-CN.mdx @@ -0,0 +1,66 @@ +# Coin 和 Fungible Token + +import { Callout, FileTree } from 'nextra/components' + +在 Rooch 中,`Coin` 是 `Fungible Token` 的具体实现。它包含在 RoochFramework 的 [`coin` 模块](https://github.com/rooch-network/rooch/blob/main/frameworks/rooch-framework/sources/coin.move) 中。 + + +## Coin 的类型 + +```move +struct Coin { + value: u256, +} +``` + +`Coin` 是一个泛型类型,它包含一个 `value` 字段,表示该 `Coin` 的值。`Coin` 的类型参数 `CoinType` 代表了该 `Coin` 的类型。在 Rooch 中,资产类型的唯一标识符是 `CoinType`,而不是合约地址,这点和 ERC20 标准不同。 + +比如 Rooch 中的 Gas Coin 的类型是 `0x3::gas_coin::RGas`。其中 `0x3` 是 RoochFramework 的合约地址,`gas_coin` 是模块名称,`RGas` 是类型名称,三者共同构成了唯一的类型标识符。 + +## 注册 Coin 类型 + +首先,开发者需要自定义一个 `CoinType`,然后通过 `coin::register_extend` 函数来创建出 `CoinInfo` 对象,而 `CoinInfo` 对象保存了该 `Coin` 类型的相关信息,比如名称、符号、图标、精度等,同时它也代表着对该 `Coin` 的管理权限。 + +```move + #[private_generics(CoinType)] + public fun register_extend( + name: string::String, + symbol: string::String, + icon_url: Option, + decimals: u8, + ): Object> +``` + +注意,该函数受 [`private_generics`](/build/rooch-framework/private-generics) 保护,只能在 `CoinType` 模块内调用。 + +## CoinStore + +`Coin` 类型没有任何 `ability`,所以它不能被直接存储在结构中,需要通过 `CoinStore` 来存储。系统默认会给每个地址的每种 `CoinType` 创建一个 `CoinStore`,开发者也可以通过 `coin::create_coin_store` 函数来创建 `Object>`,`CoinStore` 对象可以存储在任何结构体中。 + +```move + public fun create_coin_store(): Object> +``` + +## Private Coin 和 Public Coin + +在 Rooch 中,如果 `CoinType` 没有 `store` `ability`,那么该 `Coin` 就是 `Private Coin`,否则就是 `Public Coin`。 + +* `Private Coin` 只能由 `CoinType` 模块内部转移,不能在模块外部转移。 +* `Public Coin` 可以由任何模块转移,用户可以直接调用 `transfer::transfer_coin` 函数来转移 `Public Coin`。 + +如果开发者需要自定义 `Coin` 的转账逻辑,可以在自己的模块内,通过调用 `coin::transfer_extend` 函数来实现。 + +注意,`coin` 以及 `coin_store` 中,所有带有 `extend` 关键字的函数,都是受 [`private_generics`](/build/rooch-framework/private-generics) 保护的,表示这些函数是给 `CoinType` 模块开发者用来扩展的。 + + +本节内容正在完善中。需要补充更多的关于 Coin 的方法的说明: + +* `mint` 和 `burn` 方法。 +* `coin_store` 相关方法。 +* `account_coin_store` 相关方法。 + + +## Coins 例子 + +* [private_coin](https://github.com/rooch-network/rooch/blob/main/examples/coins/sources/private_coin.move) +* [fixed_supply_coin](https://github.com/rooch-network/rooch/blob/main/examples/coins/sources/fixed_supply_coin.move) \ No newline at end of file diff --git a/docs/website/pages/learn/core-concepts/rgas.en-US.mdx b/docs/website/pages/learn/core-concepts/rgas.en-US.mdx new file mode 100644 index 0000000000..015245f03a --- /dev/null +++ b/docs/website/pages/learn/core-concepts/rgas.en-US.mdx @@ -0,0 +1,61 @@ +# RGas + +import { Callout, FileTree } from 'nextra/components' + +`RGas` is the native Gas token of the Rooch network, belonging to the [Coin](/learn/core-concepts/coins) type. + +## Basic Information + +* Unique identifier: `0x3::gas_coin::RGas` +* Name: Rooch Gas Coin +* Symbol: RGAS +* Precision: 8 (8 decimal places) + +## Purpose + +RGas is primarily used to pay transaction fees on the Rooch network. Users need to consume a certain amount of RGas to pay for computation and storage costs when executing transactions. + +## Distribution Method + +1. Initial allocation: At Genesis, 500 million RGas (`500,000,000.00000000`) were allocated to the Rooch DAO multi-signature account. This is equivalent to Rooch DAO lending 500 million RGas to the protocol to bootstrap the [PreMainnet](/learn/miscellaneous/roadmap#premainnet) ecosystem. + +2. Initial pricing: 1 RGas = 0.01 USD + +3. Allocation details: + - 100 million RGas (`100,000,000.00000000`) are used for airdrops to users and developers to incentivize them to use the Rooch network. This portion is considered protocol debt and will be repaid through future Sequencer transaction fee income. + - The remaining 400 million RGas (`400,000,000.00000000`) are held by the Rooch DAO multi-signature account, considered as Rooch DAO's liability, to be repaid by Rooch DAO. + +4. After Mainnet launch: RGas will be minted by collateralizing Mainnet assets, and its price will be determined by the market. + +## How to Obtain + +### 1. Through Faucets + +Both Rooch PreMainnet and Testnet provide faucet services where users can obtain RGas for free. + +Conditions for using the PreMainnet faucet: +- The receiving address must have a BTC balance on the Bitcoin Mainnet +- The amount of RGas received is related to the BTC balance +- Each address can only claim once + +### 2. Direct Purchase with BTC + +Users can directly transfer BTC to the Rooch DAO multi-signature address on the Bitcoin Mainnet to receive an equivalent value of RGas. + +- Rooch DAO multi-signature address: `bc1prcajaj9n7e29u4dfp33x3hcf52yqeegspdpcd79pqu4fpr6llx4sugkfjt` +- RGas price: Obtained through Oracle, based on the Bitcoin price at the time of BTC transfer confirmation + +## Distribution of Transaction Gas Fees + +The Gas fee for each transaction will be distributed according to the following proportions: + +1. Sequencer: 30% + - Goes to the sequencer that ordered the transaction + +2. Application Developer: 30% + - Goes to the developer of the entry function contract called by the transaction + - If the entry contract is a system Framework contract, this portion goes to the Rooch network + +3. Rooch Network: 40% + - Before Mainnet launch: Used to repay the debt from Gas airdrops + - After Mainnet launch: Used to buy back Mainnet tokens diff --git a/docs/website/pages/learn/core-concepts/rgas.zh-CN.mdx b/docs/website/pages/learn/core-concepts/rgas.zh-CN.mdx new file mode 100644 index 0000000000..7746b33520 --- /dev/null +++ b/docs/website/pages/learn/core-concepts/rgas.zh-CN.mdx @@ -0,0 +1,64 @@ +# RGas + +import { Callout, FileTree } from 'nextra/components' + +`RGas` 是 Rooch 网络的原生 Gas 代币,属于 [Coin](/learn/core-concepts/coins) 类型。 + +## 基本信息 + +* 唯一标识:`0x3::gas_coin::RGas` +* 名称:Rooch Gas Coin +* 符号:RGAS +* 精度:8(小数点后8位) + +## 用途 + +RGas 主要用于支付 Rooch 网络上的交易费用。用户在执行交易时,需要消耗一定数量的 RGas 来支付计算和存储成本。 + +## 分发方式 + +1. 初始分配:在创世(Genesis)时,5亿 RGas(`500,000,000.00000000`)被分配给 Rooch DAO 多签账户。这相当于 Rooch DAO 向协议借出 5 亿个 RGas,用于启动 [PreMainnet](/learn/miscellaneous/roadmap#premainnet) 生态。 + +2. 初始定价:1 RGas = 0.01 USD + +3. 分配明细: + - 1亿 RGas(`100,000,000.00000000`)用于空投给用户和开发者,以激励他们使用 Rooch 网络。这部分被视为协议债务,将通过未来 Sequencer 的交易费收入来偿还。 + - 剩余 4亿 RGas(`400,000,000.00000000`)由 Rooch DAO 多签账户持有,作为 Rooch DAO 的负债,需要由 Rooch DAO 偿还。 + +4. 主网启动后:RGas 将通过抵押主网资产的方式铸造,价格将由市场决定。 + +## 获取方式 + +### 1. 通过水龙头获取 + +Rooch PreMainnet 和 Testnet 都提供了水龙头服务,用户可以通过这些水龙头免费获取 RGas。 + +PreMainnet 水龙头的使用条件: +- 领取地址必须在 Bitcoin 主网上有 BTC 余额 +- 获取的 RGas 数量与 BTC 余额相关 +- 每个地址仅能领取一次 + +### 2. 直接用 BTC 购买 + +用户可以直接在 Bitcoin 主网上向 Rooch DAO 多签地址转账 BTC,即可获得等值的 RGas。 + +- Rooch DAO 多签地址:`bc1prcajaj9n7e29u4dfp33x3hcf52yqeegspdpcd79pqu4fpr6llx4sugkfjt` +- RGas 价格:通过 Oracle 获取,以 BTC 转账交易确认时的 Bitcoin 价格为准 + +## 交易 Gas 费的分配 + +每笔交易的 Gas 费用将按以下比例分配: + +1. 排序器(Sequencer):30% + - 给该交易排序的排序器获得 + +2. 应用开发者:30% + - 交易调用的入口合约(entry function)开发者获得 + - 如果入口合约是系统 Framework 合约,则这部分归入 Rooch 网络 + +3. Rooch 网络:40% + - 主网启动前:用于归还空投 Gas 的债务 + - 主网启动后:用于回购主网代币 + +以上分配比例会根据 PreMainnet 的运行情况进行调整,最终形成 Rooch 的经济模型,在 Mainnet 上实施。 + diff --git a/docs/website/pages/learn/core-concepts/token.en-US.mdx b/docs/website/pages/learn/core-concepts/token.en-US.mdx deleted file mode 100644 index e887d745b6..0000000000 --- a/docs/website/pages/learn/core-concepts/token.en-US.mdx +++ /dev/null @@ -1 +0,0 @@ -# Token diff --git a/docs/website/pages/learn/core-concepts/token.zh-CN.mdx b/docs/website/pages/learn/core-concepts/token.zh-CN.mdx deleted file mode 100644 index e887d745b6..0000000000 --- a/docs/website/pages/learn/core-concepts/token.zh-CN.mdx +++ /dev/null @@ -1 +0,0 @@ -# Token diff --git a/docs/website/pages/learn/miscellaneous/roadmap.en-US.mdx b/docs/website/pages/learn/miscellaneous/roadmap.en-US.mdx index 65c1fb1afb..fb2f3ba9d9 100644 --- a/docs/website/pages/learn/miscellaneous/roadmap.en-US.mdx +++ b/docs/website/pages/learn/miscellaneous/roadmap.en-US.mdx @@ -54,4 +54,35 @@ Implement an application network based on [DSTP](/learn/in-depth-tech/dstp), exp 2. Collaborate with ecosystem partners to provide more DA and security options for VApp. 3. Implement state channel applications based on DSTP and explore incentive models on the P2P network. - \ No newline at end of file + + +## PreMainnet + +PreMainnet is Rooch's pre-release mainnet. We will conduct the following work on PreMainnet: + +1. Gradual iteration and improvement +2. Enhancement of security +3. Implementation of decentralization +4. Exploration of application scenarios in the Bitcoin ecosystem +5. Gradual transition to the official Mainnet + +Key features of PreMainnet: + +1. Synchronization and Compatibility: PreMainnet will synchronize transactions from the Bitcoin mainnet, using Bitcoin mainnet addresses and assets. Its network ID will be the same as the future Mainnet. + +2. Data Continuity: User application data and assets on PreMainnet will seamlessly migrate to Mainnet, ensuring that user interests are preserved. + +3. Contract Deployment Strategy: + - Initial phase: Adopt a whitelist system, limiting contract deployment. + - Later phase: Gradually transition to an open deployment model. + +4. Operation and Security Measures: + - Initially, the Rooch development team will be responsible for running the Sequencer. + - If serious security issues are discovered, the following measures will be taken: + a. Pause Sequencer operation + b. Fix the issue + c. Roll back transactions if necessary + +5. Token Usage: Only [RGas](/learn/core-concepts/rgas) will be used to pay for Gas fees on PreMainnet. Rooch's mainnet token will be launched on the official Mainnet. + +Through this PreMainnet phase, we aim to lay a solid foundation for Rooch's official mainnet, ensuring the network's security, stability, and scalability. \ No newline at end of file diff --git a/docs/website/pages/learn/miscellaneous/roadmap.zh-CN.mdx b/docs/website/pages/learn/miscellaneous/roadmap.zh-CN.mdx index 126fc353eb..4445cd5214 100644 --- a/docs/website/pages/learn/miscellaneous/roadmap.zh-CN.mdx +++ b/docs/website/pages/learn/miscellaneous/roadmap.zh-CN.mdx @@ -54,3 +54,33 @@ Root 到 Bitcoin 网络,运行 Rooch PreMainnet,并升级到 Mainnet。探 3. 实现基于 DSTP 的状态通道应用,探索 P2P 网络上的激励模型。 + +## PreMainnet + +PreMainnet 是 Rooch 的预发布主网。我们将在 PreMainnet 上进行以下工作: + +1. 逐步迭代和改进 +2. 提升安全性 +3. 实现去中心化 +4. 探索 Bitcoin 生态的应用场景 +5. 逐步过渡到正式的 Mainnet + +PreMainnet 的主要特点: + +1. 同步与兼容性:PreMainnet 会同步 Bitcoin 主网的交易,使用 Bitcoin 主网的地址和资产。其网络 ID 与未来的 Mainnet 相同。 + +2. 数据延续性:用户在 PreMainnet 上的应用数据和资产将无缝迁移到 Mainnet,确保用户利益不会丢失。 + +3. 合约部署策略: + - 初期:采用白名单制度,限制合约部署。 + - 后期:逐步过渡到开放部署模式。 + +4. 运营与安全措施: + - 初期由 Rooch 开发团队负责运行 Sequencer。 + - 如发现严重安全问题,将采取以下措施: + a. 暂停 Sequencer 运行 + b. 修复问题并升级网络,必要时回滚交易 + +5. 代币使用:PreMainnet 上仅使用 [RGas](/learn/core-concepts/rgas) 支付 Gas 费。Rooch 的主网代币将在正式 Mainnet 上发布。 + +通过这个 PreMainnet 阶段,我们旨在为 Rooch 的正式主网打下坚实的基础,确保网络的安全性、稳定性和可扩展性。 \ No newline at end of file diff --git a/docs/website/public/blog/hacker-house.jpg b/docs/website/public/blog/hacker-house.jpg new file mode 100644 index 0000000000..2ee1f8470c Binary files /dev/null and b/docs/website/public/blog/hacker-house.jpg differ diff --git a/frameworks/bitcoin-move/doc/README.md b/frameworks/bitcoin-move/doc/README.md index 2cf05ae339..c3ff1b6460 100644 --- a/frameworks/bitcoin-move/doc/README.md +++ b/frameworks/bitcoin-move/doc/README.md @@ -12,6 +12,7 @@ This is the reference documentation of the Bitcoin Move Framework. ## Index +- [`0x4::bbn`](bbn.md#0x4_bbn) - [`0x4::bitcoin`](bitcoin.md#0x4_bitcoin) - [`0x4::bitcoin_hash`](bitcoin_hash.md#0x4_bitcoin_hash) - [`0x4::bitcoin_multisign_validator`](bitcoin_multisign_validator.md#0x4_bitcoin_multisign_validator) diff --git a/frameworks/bitcoin-move/doc/bbn.md b/frameworks/bitcoin-move/doc/bbn.md new file mode 100644 index 0000000000..5091c09e3e --- /dev/null +++ b/frameworks/bitcoin-move/doc/bbn.md @@ -0,0 +1,153 @@ + + + +# Module `0x4::bbn` + + + +- [Resource `BBNGlobalParam`](#0x4_bbn_BBNGlobalParam) +- [Resource `BBNGlobalParams`](#0x4_bbn_BBNGlobalParams) +- [Struct `BBNOpReturnData`](#0x4_bbn_BBNOpReturnData) +- [Constants](#@Constants_0) +- [Function `genesis_init`](#0x4_bbn_genesis_init) +- [Function `try_get_bbn_op_return_data`](#0x4_bbn_try_get_bbn_op_return_data) +- [Function `try_get_staking_output`](#0x4_bbn_try_get_staking_output) +- [Function `derive_bbn_utxo`](#0x4_bbn_derive_bbn_utxo) + + +
use 0x1::option;
+use 0x1::vector;
+use 0x2::object;
+use 0x3::bitcoin_address;
+use 0x4::bitcoin;
+use 0x4::script_buf;
+use 0x4::types;
+use 0x4::utxo;
+
+ + + + + +## Resource `BBNGlobalParam` + + + +
struct BBNGlobalParam has store, key
+
+ + + + + +## Resource `BBNGlobalParams` + + + +
struct BBNGlobalParams has key
+
+ + + + + +## Struct `BBNOpReturnData` + + + +
struct BBNOpReturnData has copy, drop, store
+
+ + + + + +## Constants + + + + + + +
const ErrorNotBabylonOpReturn: u64 = 2;
+
+ + + + + + + +
const ErrorNotBabylonUTXO: u64 = 0;
+
+ + + + + + + +
const ErrorNotTransaction: u64 = 1;
+
+ + + + + + + +
const ErrorTransactionLockTime: u64 = 3;
+
+ + + + + + + +
const UNSPENDABLEKEYPATHKEY: vector<u8> = [48, 50, 53, 48, 57, 50, 57, 98, 55, 52, 99, 49, 97, 48, 52, 57, 53, 52, 98, 55, 56, 98, 52, 98, 54, 48, 51, 53, 101, 57, 55, 97, 53, 101, 48, 55, 56, 97, 53, 97, 48, 102, 50, 56, 101, 99, 57, 54, 100, 53, 52, 55, 98, 102, 101, 101, 57, 97, 99, 101, 56, 48, 51, 97, 99, 48];
+
+ + + + + +## Function `genesis_init` + + + +
public(friend) fun genesis_init()
+
+ + + + + +## Function `try_get_bbn_op_return_data` + + + +
public fun try_get_bbn_op_return_data(transaction: types::Transaction): (bool, u64, bbn::BBNOpReturnData)
+
+ + + + + +## Function `try_get_staking_output` + + + +
public fun try_get_staking_output(transaction: types::Transaction, staking_output_script: &vector<u8>): (bool, u64, option::Option<object::ObjectID>)
+
+ + + + + +## Function `derive_bbn_utxo` + + + +
public fun derive_bbn_utxo(utxo_obj: &object::Object<utxo::UTXO>)
+
diff --git a/frameworks/bitcoin-move/doc/genesis.md b/frameworks/bitcoin-move/doc/genesis.md index eb9e4c2473..afd598f810 100644 --- a/frameworks/bitcoin-move/doc/genesis.md +++ b/frameworks/bitcoin-move/doc/genesis.md @@ -14,6 +14,7 @@ use 0x2::signer; use 0x2::tx_context; use 0x3::bitcoin_address; +use 0x4::bbn; use 0x4::bitcoin; use 0x4::bitcoin_multisign_validator; use 0x4::multisign_account; diff --git a/frameworks/bitcoin-move/doc/script_buf.md b/frameworks/bitcoin-move/doc/script_buf.md index 5bf833b1ab..260f310a96 100644 --- a/frameworks/bitcoin-move/doc/script_buf.md +++ b/frameworks/bitcoin-move/doc/script_buf.md @@ -20,6 +20,7 @@ - [Function `is_witness_program`](#0x4_script_buf_is_witness_program) - [Function `witness_program`](#0x4_script_buf_witness_program) - [Function `is_op_return`](#0x4_script_buf_is_op_return) +- [Function `unpack_bbn_stake_data`](#0x4_script_buf_unpack_bbn_stake_data) - [Function `push_opcode`](#0x4_script_buf_push_opcode) - [Function `push_data`](#0x4_script_buf_push_data) - [Function `push_int`](#0x4_script_buf_push_int) @@ -68,6 +69,15 @@ + + + + +
const ErrorInvalidBytesLen: u64 = 2;
+
+ + + @@ -228,6 +238,17 @@ Checks if the given script is an OP_RETURN script. + + +## Function `unpack_bbn_stake_data` + + + +
public fun unpack_bbn_stake_data(self: &script_buf::ScriptBuf): (vector<u8>, u64, vector<u8>, vector<u8>, u16)
+
+ + + ## Function `push_opcode` diff --git a/frameworks/bitcoin-move/sources/bbn.move b/frameworks/bitcoin-move/sources/bbn.move new file mode 100644 index 0000000000..48a1cbadbe --- /dev/null +++ b/frameworks/bitcoin-move/sources/bbn.move @@ -0,0 +1,255 @@ +module bitcoin_move::bbn { + + use std::option; + use std::option::{is_none, Option, none, is_some, some}; + use std::vector; + use std::vector::{length, borrow}; + use bitcoin_move::bitcoin; + use bitcoin_move::utxo::UTXO; + use bitcoin_move::types; + use bitcoin_move::utxo; + use bitcoin_move::script_buf; + use bitcoin_move::types::{ + Transaction, + tx_id, + tx_output, + txout_value, + tx_lock_time, + txout_script_pubkey + }; + use bitcoin_move::bitcoin::get_tx_height; + use rooch_framework::bitcoin_address::{ + derive_bitcoin_taproot_address_from_pubkey, + to_rooch_address + }; + use bitcoin_move::script_buf::{unpack_bbn_stake_data}; + use moveos_std::object::{Object, ObjectID}; + use moveos_std::object; + + friend bitcoin_move::genesis; + + struct BBNGlobalParam has key, store { + version: u64, + activation_height: u64, + staking_cap: u64, + cap_height: u64, + tag: vector, + covenant_pks: vector>, + covenant_quorum: u32, + unbonding_time: u16, + unbonding_fee: u64, + max_staking_amount: u64, + min_staking_amount: u64, + min_staking_time: u16, + max_staking_time: u16, + confirmation_depth: u16 + } + + struct BBNGlobalParams has key { + bbn_global_param: vector + } + + struct BBNOpReturnData has copy, store, drop { + tag: vector, + version: u64, + staker_pub_key: vector, + finality_provider_pub_key: vector, + staking_time: u16 + } + + const UNSPENDABLEKEYPATHKEY: vector = b"0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"; + + const ErrorNotBabylonUTXO: u64 = 0; + const ErrorNotTransaction: u64 = 1; + const ErrorNotBabylonOpReturn: u64 = 2; + const ErrorTransactionLockTime: u64 = 3; + + public(friend) fun genesis_init() { + // TODO here just add bbn test-4 version 2 + let bbn_global_params_2 = BBNGlobalParam { + version: 2, + activation_height: 200665, + staking_cap: 0, + cap_height: 201385, + tag: b"62627434", + covenant_pks: vector[ + b"03fa9d882d45f4060bdb8042183828cd87544f1ea997380e586cab77d5fd698737", + b"020aee0509b16db71c999238a4827db945526859b13c95487ab46725357c9a9f25", + b"0217921cf156ccb4e73d428f996ed11b245313e37e27c978ac4d2cc21eca4672e4", + b"02113c3a32a9d320b72190a04a020a0db3976ef36972673258e9a38a364f3dc3b0", + b"0379a71ffd71c503ef2e2f91bccfc8fcda7946f4653cef0d9f3dde20795ef3b9f0", + b"023bb93dfc8b61887d771f3630e9a63e97cbafcfcc78556a474df83a31a0ef899c", + b"03d21faf78c6751a0d38e6bd8028b907ff07e9a869a43fc837d6b3f8dff6119a36", + b"0340afaf47c4ffa56de86410d8e47baa2bb6f04b604f4ea24323737ddc3fe092df", + b"03f5199efae3f28bb82476163a7e458c7ad445d9bffb0682d10d3bdb2cb41f8e8e" + ], + covenant_quorum: 6, + unbonding_time: 1008, + unbonding_fee: 10000, + max_staking_amount: 5000000, + min_staking_amount: 50000, + min_staking_time: 64000, + max_staking_time: 64000, + confirmation_depth: 10 + }; + let obj = + object::new_named_object( + BBNGlobalParams { bbn_global_param: vector[bbn_global_params_2] } + ); + object::to_shared(obj); + } + + fun borrow_bbn_params(): &Object { + let object_id = object::named_object_id(); + object::borrow_object(object_id) + } + + fun borrow_bbn_params_mut(): &mut Object { + let object_id = object::named_object_id(); + object::borrow_mut_object_shared(object_id) + } + + public fun try_get_bbn_op_return_data(transaction: Transaction): + (bool, u64, BBNOpReturnData) { + let bbn_op_return_data = BBNOpReturnData { + tag: vector[], + version: 0, + staker_pub_key: vector[], + finality_provider_pub_key: vector[], + staking_time: 0 + }; + let tx_output = tx_output(&transaction); + if (vector::length(tx_output) < 2) { + return (false, 0, bbn_op_return_data) + }; + + // this case should not happen as standard bitcoin node propagation rules + // disallow multiple op return outputs in a single transaction. However, miner could + // include multiple op return outputs in a single transaction. In such case, we should + // return an error. + let index = 0; + let i = 0; + while (i < length(tx_output)) { + let output = borrow(tx_output, i); + let (tag, version, staker_pub_key, finality_provider_pub_key, staking_time) = + unpack_bbn_stake_data(txout_script_pubkey(output)); + bbn_op_return_data.tag = tag; + bbn_op_return_data.version = version; + bbn_op_return_data.staker_pub_key = staker_pub_key; + bbn_op_return_data.finality_provider_pub_key = finality_provider_pub_key; + bbn_op_return_data.staking_time = staking_time; + if (vector::length(&bbn_op_return_data.tag) != 0) { break }; + index = index + 1; + i = i + 1; + }; + if (vector::length(&bbn_op_return_data.tag) == 0) { + return (false, 0, bbn_op_return_data) + }; + let option_tx_height = get_tx_height(tx_id(&transaction)); + if (is_none(&option_tx_height)) { + return (false, 0, bbn_op_return_data) + }; + let tx_height = option::destroy_some(option_tx_height); + let bbn_params = object::borrow(borrow_bbn_params()); + let i = 0; + while (i < length(&bbn_params.bbn_global_param)) { + let param = borrow(&bbn_params.bbn_global_param, i); + i = i + 1; + if (bbn_op_return_data.version != param.version + || bbn_op_return_data.tag != param.tag + || tx_height < param.activation_height + || param.covenant_quorum > (length(¶m.covenant_pks) as u32)) { + continue + }; + if (param.cap_height != 0 + && tx_height > (param.activation_height + param.cap_height)) { + continue + }; + if (bbn_op_return_data.staking_time < param.min_staking_time + || bbn_op_return_data.staking_time > param.max_staking_time) { + continue + }; + if (!vector::contains( + ¶m.covenant_pks, &bbn_op_return_data.finality_provider_pub_key + )) { + continue + }; + return (true, index, bbn_op_return_data) + }; + return (false, 0, bbn_op_return_data) + } + + public fun try_get_staking_output( + transaction: Transaction, staking_output_script: &vector + ): (bool, u64, Option) { + let tx_outputs = tx_output(&transaction); + let tx_id = tx_id(&transaction); + if (vector::length(tx_outputs) == 0) { + return (false, 0, none()) + }; + let index = 0; + + // should not multiple staking outputs + while (index < length(tx_outputs)) { + let tx_output = borrow(tx_outputs, index); + if (script_buf::bytes(txout_script_pubkey(tx_output)) + == staking_output_script) { + let out_point = types::new_outpoint( + tx_id, (txout_value(tx_output) as u32) + ); + return (true, index, option::some(utxo::derive_utxo_id(out_point))) + }; + index = index + 1; + }; + return (false, index, none()) + } + + public fun derive_bbn_utxo(utxo_obj: &Object) { + // assert!(object::owner(utxo_obj) == @bitcoin_move, ErrorNotBabylonUTXO); + let utxo = object::borrow(utxo_obj); + let txid = utxo::txid(utxo); + let option_tx = bitcoin::get_tx(txid); + assert!(is_some(&option_tx), ErrorNotTransaction); + let transaction = option::destroy_some(option_tx); + let (is_true, op_return_index, op_return_data) = + try_get_bbn_op_return_data(transaction); + assert!(is_true, ErrorNotBabylonOpReturn); + // TODO here should replace to check staking output + // try_get_staking_output() + + assert!( + tx_lock_time(&transaction) >= (op_return_data.staking_time as u32), + ErrorTransactionLockTime + ); + let tx_outputs = tx_output(&transaction); + let index = 0; + // TODO bbn should not multiple staking outputs, we temporarily support + while (index < length(tx_outputs)) { + let tx_output = borrow(tx_outputs, index); + if (index == op_return_index) { + continue + }; + let out_point = types::new_outpoint(txid, (txout_value(tx_output) as u32)); + let borrow_utxo = utxo::borrow_utxo(out_point); + if (object::owner(borrow_utxo) != @bitcoin_move) { + continue + }; + let utxo_id = utxo::derive_utxo_id(out_point); + let utxo_obj = utxo::take(utxo_id); + utxo::add_temp_state(&mut utxo_obj, op_return_data); + // TODO here should modify sender to trigger event queue? + utxo::transfer( + utxo_obj, + some(@bitcoin_move), + pubkey_to_rooch_address(&op_return_data.staker_pub_key) + ); + index = index + 1; + }; + } + + // TODO build stake info + + fun pubkey_to_rooch_address(pubkey: &vector): address { + to_rooch_address(&derive_bitcoin_taproot_address_from_pubkey(pubkey)) + } +} diff --git a/frameworks/bitcoin-move/sources/genesis.move b/frameworks/bitcoin-move/sources/genesis.move index 7ed4e6814c..2a613ce4ed 100644 --- a/frameworks/bitcoin-move/sources/genesis.move +++ b/frameworks/bitcoin-move/sources/genesis.move @@ -3,6 +3,7 @@ module bitcoin_move::genesis{ use std::option; + use bitcoin_move::bbn; use moveos_std::tx_context; use moveos_std::signer; use rooch_framework::bitcoin_address::{Self, BitcoinAddress}; @@ -40,6 +41,7 @@ module bitcoin_move::genesis{ network::genesis_init(genesis_context.network); utxo::genesis_init(); ord::genesis_init(); + bbn::genesis_init(); bitcoin::genesis_init(&genesis_account, genesis_context.genesis_block_height, genesis_context.genesis_block_hash); pending_block::genesis_init(genesis_context.reorg_block_count); bitcoin_multisign_validator::genesis_init(); diff --git a/frameworks/bitcoin-move/sources/script_buf.move b/frameworks/bitcoin-move/sources/script_buf.move index b8d7d7ac06..bb302bc6ca 100644 --- a/frameworks/bitcoin-move/sources/script_buf.move +++ b/frameworks/bitcoin-move/sources/script_buf.move @@ -6,6 +6,7 @@ module bitcoin_move::script_buf{ use bitcoin_move::opcode; const ErrorInvalidKeySize: u64 = 1; + const ErrorInvalidBytesLen: u64 = 2; const BITCOIN_X_ONLY_PUBKEY_SIZE: u64 = 32; const BITCOIN_PUBKEY_SIZE: u64 = 33; @@ -93,6 +94,37 @@ module bitcoin_move::script_buf{ *vector::borrow(&self.bytes, 0) == opcode::op_return() } + public fun unpack_bbn_stake_data(self: &ScriptBuf): (vector, u64, vector, vector, u16){ + // 1. OP_RETURN opcode - which signalizes that data is provably unspendable + // 2. OP_DATA_71 opcode - which pushes 71 bytes of data to the stack + if (vector::length(&self.bytes) != 73 || *vector::borrow(&self.bytes, 0) != opcode::op_return() || *vector::borrow(&self.bytes, 1) != opcode::op_pushbytes_71()){ + return (vector[], 0, vector[], vector[], 0) + }; + let tag = vector::slice(&self.bytes, 2, 6); + let version = bytes_to_u64(vector::slice(&self.bytes, 6, 7)); + let staker_pub_key = vector::slice(&self.bytes, 7, 39); + let finality_provider_pub_key = vector::slice(&self.bytes, 39, 71); + let staking_time = bytes_to_u16(vector::slice(&self.bytes, 71, 73)); + return (tag, version, staker_pub_key, finality_provider_pub_key, staking_time) + } + + fun bytes_to_u16(bytes: vector): u16 { + assert!(vector::length(&bytes) == 2, ErrorInvalidBytesLen); + let high_byte = vector::borrow(&bytes, 0); + let low_byte = vector::borrow(&bytes, 1); + ((*high_byte as u16) << 8) | (*low_byte as u16) + } + + fun bytes_to_u64(bytes: vector): u64 { + let value = 0u64; + let i = 0u64; + while (i < 8) { + value = value | ((*vector::borrow(&bytes, i) as u64) << ((8 * (7 - i)) as u8)); + i = i + 1; + }; + return value + } + // ====== Script Builder ====== public fun push_opcode(self: &mut ScriptBuf, opcode: u8) { diff --git a/frameworks/bitcoin-move/sources/utxo.move b/frameworks/bitcoin-move/sources/utxo.move index 7930a89177..26988065eb 100644 --- a/frameworks/bitcoin-move/sources/utxo.move +++ b/frameworks/bitcoin-move/sources/utxo.move @@ -17,6 +17,7 @@ module bitcoin_move::utxo{ friend bitcoin_move::ord; friend bitcoin_move::bitcoin; friend bitcoin_move::inscription_updater; + friend bitcoin_move::bbn; const TEMPORARY_AREA: vector = b"temporary_area"; diff --git a/frameworks/moveos-stdlib/src/natives/moveos_stdlib/json.rs b/frameworks/moveos-stdlib/src/natives/moveos_stdlib/json.rs index b3dcc82476..aa32cbd49e 100644 --- a/frameworks/moveos-stdlib/src/natives/moveos_stdlib/json.rs +++ b/frameworks/moveos-stdlib/src/natives/moveos_stdlib/json.rs @@ -104,7 +104,7 @@ fn parse_struct_value_from_json( Err(anyhow::anyhow!("Invalid std option layout")) } else if struct_type == &SimpleMap::::struct_tag() { let key_value_pairs = json_obj_to_key_value_pairs(json_value)?; - let mut key_values = Vec::new(); + let mut key_values = Vec::with_capacity(key_value_pairs.len()); for (key, value) in key_value_pairs { key_values.push(Value::struct_(Struct::pack(vec![ Value::struct_(Struct::pack(vec![Value::vector_u8( @@ -243,7 +243,7 @@ fn parse_move_value_from_json( fn json_obj_to_key_value_pairs(json_obj: &JsonValue) -> Result> { if let JsonValue::Object(obj) = json_obj { - let mut key_value_pairs = Vec::new(); + let mut key_value_pairs = Vec::with_capacity(obj.len()); for (key, value) in obj.iter() { let key = key.to_string(); let value = match value { @@ -394,7 +394,7 @@ fn serialize_move_value_to_json(layout: &MoveTypeLayout, value: &MoveValue) -> R JsonValue::Array(json_vec) } else { - let mut json_vec = Vec::new(); + let mut json_vec = Vec::with_capacity(vec.len()); for item in vec.iter() { let json_value = serialize_move_value_to_json(layout, item)?; diff --git a/frameworks/rooch-nursery/src/natives/wasm.rs b/frameworks/rooch-nursery/src/natives/wasm.rs index 454e5f8641..77899bbb28 100644 --- a/frameworks/rooch-nursery/src/natives/wasm.rs +++ b/frameworks/rooch-nursery/src/natives/wasm.rs @@ -453,7 +453,7 @@ fn execute_wasm_function_inner( gas_meter.reset(); drop(gas_meter); - let mut wasm_func_args = Vec::new(); + let mut wasm_func_args = Vec::with_capacity(func_args.len()); for arg in func_args.iter() { wasm_func_args.push(wasmer::Value::I32(*arg as i32)); } diff --git a/infra/rooch-portal-v2/.eslintrc.js b/infra/rooch-portal-v2/.eslintrc.js index c4bea28110..9fc5442377 100644 --- a/infra/rooch-portal-v2/.eslintrc.js +++ b/infra/rooch-portal-v2/.eslintrc.js @@ -31,6 +31,7 @@ module.exports = { 'no-console': 0, 'no-unused-vars': 0, 'no-nested-ternary': 0, + 'no-shadow': 'off', 'no-param-reassign': 0, 'no-underscore-dangle': 0, 'no-restricted-exports': 0, @@ -44,6 +45,7 @@ module.exports = { '@typescript-eslint/consistent-type-exports': 1, '@typescript-eslint/consistent-type-imports': 1, '@typescript-eslint/no-unused-vars': [1, { args: 'none' }], + '@typescript-eslint/no-shadow': 0, // react 'react/no-children-prop': 0, 'react/react-in-jsx-scope': 0, diff --git a/infra/rooch-portal-v2/contract/gas_market/Move.toml b/infra/rooch-portal-v2/contract/gas_market/Move.toml index 31223a9159..38f8493849 100644 --- a/infra/rooch-portal-v2/contract/gas_market/Move.toml +++ b/infra/rooch-portal-v2/contract/gas_market/Move.toml @@ -1,6 +1,6 @@ [package] name = "gas_market" -version = "0.0.1" +version = "1.0.0" [dependencies] MoveStdlib = { local = "../../../../frameworks/move-stdlib" } @@ -10,6 +10,8 @@ BitcoinMove = { local = "../../../../frameworks/bitcoin-move" } [addresses] +#bc1prcajaj9n7e29u4dfp33x3hcf52yqeegspdpcd79pqu4fpr6llx4sugkfjt +#0x701c21bf1c8cd5af8c42983890d8ca55e7a820171b8e744c13f2d9998bf76cc3 gas_market = "_" std = "0x1" moveos_std = "0x2" diff --git a/infra/rooch-portal-v2/contract/gas_market/README.md b/infra/rooch-portal-v2/contract/gas_market/README.md new file mode 100644 index 0000000000..d1e5770806 --- /dev/null +++ b/infra/rooch-portal-v2/contract/gas_market/README.md @@ -0,0 +1,16 @@ +# GasMarket and GasFaucet + +1. build package + +```bash +rooch move build -p infra/rooch-portal-v2/contract/gas_market --named-addresses gas_market=bc1prcajaj9n7e29u4dfp33x3hcf52yqeegspdpcd79pqu4fpr6llx4sugkfjt +``` + +2. build tx + +```bash +rooch tx build --sender bc1prcajaj9n7e29u4dfp33x3hcf52yqeegspdpcd79pqu4fpr6llx4sugkfjt --function 0x2::module_store::publish_package_entry --args file:infra/rooch-portal-v2/contract/gas_market/build/gas_market/package.rpd +``` + +3. sign tx +4. submit tx \ No newline at end of file diff --git a/infra/rooch-portal-v2/contract/gas_market/released/1/package.rpd b/infra/rooch-portal-v2/contract/gas_market/released/1/package.rpd new file mode 100644 index 0000000000..881bba5c7c Binary files /dev/null and b/infra/rooch-portal-v2/contract/gas_market/released/1/package.rpd differ diff --git a/infra/rooch-portal-v2/contract/gas_market/sources/admin.move b/infra/rooch-portal-v2/contract/gas_market/sources/admin.move index f4107f493f..713a49ec12 100644 --- a/infra/rooch-portal-v2/contract/gas_market/sources/admin.move +++ b/infra/rooch-portal-v2/contract/gas_market/sources/admin.move @@ -1,12 +1,16 @@ module gas_market::admin { - use moveos_std::object::{Self,to_shared}; + use moveos_std::object::{Self,transfer}; struct AdminCap has store, key {} fun init() { let admin_cap = object::new_named_object(AdminCap {}); - to_shared(admin_cap) + transfer(admin_cap, @gas_market) + } + + #[deprecated] + public entry fun fix_admin_cap() { } #[test_only] diff --git a/infra/rooch-portal-v2/next.config.mjs b/infra/rooch-portal-v2/next.config.mjs index d93b6a8d90..2b9ffdbc2d 100644 --- a/infra/rooch-portal-v2/next.config.mjs +++ b/infra/rooch-portal-v2/next.config.mjs @@ -6,7 +6,7 @@ const isStaticExport = 'false'; const nextConfig = { compiler: { - removeConsole: true, + removeConsole: false, }, trailingSlash: false, basePath: process.env.NEXT_PUBLIC_BASE_PATH, diff --git a/infra/rooch-portal-v2/package.json b/infra/rooch-portal-v2/package.json index d5d17bf11d..4609ff86a7 100644 --- a/infra/rooch-portal-v2/package.json +++ b/infra/rooch-portal-v2/package.json @@ -41,8 +41,8 @@ "@mui/x-data-grid": "^7.7.0", "@mui/x-date-pickers": "^7.7.0", "@mui/x-tree-view": "^7.7.0", - "@roochnetwork/rooch-sdk": "^0.2.4", - "@roochnetwork/rooch-sdk-kit": "^0.2.4", + "@roochnetwork/rooch-sdk": "0.2.6", + "@roochnetwork/rooch-sdk-kit": "0.2.6", "@tanstack/react-query": "^5.51.11", "@types/react-syntax-highlighter": "^15.5.13", "autoprefixer": "^10.4.19", @@ -54,11 +54,13 @@ "framer-motion": "^11.2.10", "next": "^14.2.4", "nprogress": "^0.2.0", + "numeral": "^2.0.6", "postcss": "^8.4.39", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.51.5", "react-syntax-highlighter": "^15.5.0", + "react-use": "^17.5.1", "simplebar-react": "^3.2.5", "sonner": "^1.5.0", "stylis": "^4.3.2", @@ -72,6 +74,7 @@ "@types/dompurify": "^3.0.5", "@types/node": "^20.14.2", "@types/nprogress": "^0.2.3", + "@types/numeral": "^2.0.5", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/stylis": "^4.2.6", diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/alert-triangle.svg b/infra/rooch-portal-v2/public/assets/icons/swap/alert-triangle.svg new file mode 100644 index 0000000000..5dd22b9606 --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/alert-triangle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/chevron-down.svg b/infra/rooch-portal-v2/public/assets/icons/swap/chevron-down.svg new file mode 100644 index 0000000000..fe729e52b8 --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/chevron-down.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/chevron-up.svg b/infra/rooch-portal-v2/public/assets/icons/swap/chevron-up.svg new file mode 100644 index 0000000000..8a3a9699fd --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/chevron-up.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/relation-stable.svg b/infra/rooch-portal-v2/public/assets/icons/swap/relation-stable.svg new file mode 100644 index 0000000000..6790e8877c --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/relation-stable.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/relation-uncorrelated.svg b/infra/rooch-portal-v2/public/assets/icons/swap/relation-uncorrelated.svg new file mode 100644 index 0000000000..18e60eeb4a --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/relation-uncorrelated.svg @@ -0,0 +1,3 @@ + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/settings.svg b/infra/rooch-portal-v2/public/assets/icons/swap/settings.svg new file mode 100644 index 0000000000..35cc555e33 --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/slippage-settings.svg b/infra/rooch-portal-v2/public/assets/icons/swap/slippage-settings.svg new file mode 100644 index 0000000000..ada709757a --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/slippage-settings.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/swap-down.svg b/infra/rooch-portal-v2/public/assets/icons/swap/swap-down.svg new file mode 100644 index 0000000000..0bb12e8609 --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/swap-down.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/swap-header-icon.svg b/infra/rooch-portal-v2/public/assets/icons/swap/swap-header-icon.svg new file mode 100644 index 0000000000..effdc29c7f --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/swap-header-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/infra/rooch-portal-v2/public/assets/icons/swap/swap-icon.svg b/infra/rooch-portal-v2/public/assets/icons/swap/swap-icon.svg new file mode 100644 index 0000000000..17e2a97bb8 --- /dev/null +++ b/infra/rooch-portal-v2/public/assets/icons/swap/swap-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/infra/rooch-portal-v2/src/app/gas-swap/page.tsx b/infra/rooch-portal-v2/src/app/gas-swap/page.tsx new file mode 100644 index 0000000000..6f0b6395b1 --- /dev/null +++ b/infra/rooch-portal-v2/src/app/gas-swap/page.tsx @@ -0,0 +1,13 @@ +import WalletGuard from 'src/components/guard/WalletGuard'; + +import GasSwapOverview from 'src/sections/gas-swap'; + +export const metadata = { title: `Purchase Gas` }; + +export default function Page() { + return ( + + + + ); +} diff --git a/infra/rooch-portal-v2/src/app/layout.tsx b/infra/rooch-portal-v2/src/app/layout.tsx index 2408429113..2bd1504e2c 100644 --- a/infra/rooch-portal-v2/src/app/layout.tsx +++ b/infra/rooch-portal-v2/src/app/layout.tsx @@ -3,15 +3,16 @@ import '@fontsource-variable/raleway/wght.css'; import '@fontsource-variable/plus-jakarta-sans/wght.css'; import type { Viewport } from 'next'; -import { headers } from 'next/headers'; +import { headers } from 'next/headers'; import '@fontsource-variable/red-hat-mono'; +import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'; + import { primary } from 'src/theme/core/palette'; import { DashboardLayout } from 'src/layouts/dashboard'; import { ThemeProvider } from 'src/theme/theme-provider'; import { schemeConfig } from 'src/theme/color-scheme-script'; -import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'; import { Snackbar } from 'src/components/snackbar'; import { ProgressBar } from 'src/components/progress-bar'; diff --git a/infra/rooch-portal-v2/src/app/rooch-dapp-provider.tsx b/infra/rooch-portal-v2/src/app/rooch-dapp-provider.tsx index a29b5c0e0f..26d079886e 100644 --- a/infra/rooch-portal-v2/src/app/rooch-dapp-provider.tsx +++ b/infra/rooch-portal-v2/src/app/rooch-dapp-provider.tsx @@ -7,12 +7,15 @@ import { RoochProvider, WalletProvider } from '@roochnetwork/rooch-sdk-kit'; import { networkConfig } from 'src/hooks/use-networks'; +import { isMainNetwork } from '../utils/env' + const queryClient = new QueryClient(); export default function RoochDappProvider({ children }: { children: ReactNode }) { + const network = isMainNetwork() ? 'mainnet' : 'testnet' return ( - + {children} diff --git a/infra/rooch-portal-v2/src/assets/icon/alert-triangle.svg b/infra/rooch-portal-v2/src/assets/icon/alert-triangle.svg new file mode 100644 index 0000000000..5dd22b9606 --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/alert-triangle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/chevron-down.svg b/infra/rooch-portal-v2/src/assets/icon/chevron-down.svg new file mode 100644 index 0000000000..fe729e52b8 --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/chevron-down.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/chevron-up.svg b/infra/rooch-portal-v2/src/assets/icon/chevron-up.svg new file mode 100644 index 0000000000..8a3a9699fd --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/chevron-up.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/relation-stable.svg b/infra/rooch-portal-v2/src/assets/icon/relation-stable.svg new file mode 100644 index 0000000000..6790e8877c --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/relation-stable.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/relation-uncorrelated.svg b/infra/rooch-portal-v2/src/assets/icon/relation-uncorrelated.svg new file mode 100644 index 0000000000..18e60eeb4a --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/relation-uncorrelated.svg @@ -0,0 +1,3 @@ + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/settings.svg b/infra/rooch-portal-v2/src/assets/icon/settings.svg new file mode 100644 index 0000000000..35cc555e33 --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/slippage-settings.svg b/infra/rooch-portal-v2/src/assets/icon/slippage-settings.svg new file mode 100644 index 0000000000..ada709757a --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/slippage-settings.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/swap-down.svg b/infra/rooch-portal-v2/src/assets/icon/swap-down.svg new file mode 100644 index 0000000000..0bb12e8609 --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/swap-down.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/swap-header-icon.svg b/infra/rooch-portal-v2/src/assets/icon/swap-header-icon.svg new file mode 100644 index 0000000000..effdc29c7f --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/swap-header-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/infra/rooch-portal-v2/src/assets/icon/swap-icon.svg b/infra/rooch-portal-v2/src/assets/icon/swap-icon.svg new file mode 100644 index 0000000000..17e2a97bb8 --- /dev/null +++ b/infra/rooch-portal-v2/src/assets/icon/swap-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/infra/rooch-portal-v2/src/components/swap/curve-type-select.tsx b/infra/rooch-portal-v2/src/components/swap/curve-type-select.tsx new file mode 100644 index 0000000000..00c233225f --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/curve-type-select.tsx @@ -0,0 +1,62 @@ +import { Stack, Button, Tooltip } from '@mui/material'; + +import { Iconify } from '../iconify'; + +import type { CurveType } from './types'; + +export interface CurveTypeSelectProps { + curveType: CurveType; + onChange: (curveType: CurveType) => void; +} + +export default function CurveTypeSelect({ curveType, onChange }: CurveTypeSelectProps) { + return ( + + onChange('uncorrelated')} + /> + onChange('stable')} + /> + + ); +} + +function OptionButton({ + curveType, + value, + icon, + tooltip, + onClick, +}: { + curveType: CurveType; + value: CurveType; + icon: string; + tooltip: string; + onClick: (curveType: CurveType) => void; +}) { + return ( + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/pool-version-select.tsx b/infra/rooch-portal-v2/src/components/swap/pool-version-select.tsx new file mode 100644 index 0000000000..915b80880a --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/pool-version-select.tsx @@ -0,0 +1,51 @@ +import { darken, ToggleButton, ToggleButtonGroup } from '@mui/material'; + +import type { PoolVersion } from './types'; + +export interface PoolVersionSelectProps { + version?: number; + onChange?: (version: PoolVersion) => void; +} + +export default function PoolVersionSelect({ version, onChange }: PoolVersionSelectProps) { + return ( + { + if (value !== null && onChange) { + onChange(value); + } + }} + sx={{ + '& .MuiToggleButton-root': { + fontSize: '0.875rem', + fontWeight: 600, + lineHeight: '100%', + color: '#9DA3B1', + border: 'none', + background: '#DCDEE1', + width: '50px', + transition: 'all 0.3s ease', + padding: '8.55px 0', + '&.Mui-selected': { + background: '#EFF0F0', + color: '#101828', + '&:hover': { + background: darken('#EFF0F0', 0.02), + }, + }, + '&:hover': { + background: darken('#DCDEE1', 0.1), + }, + }, + '& .MuiToggleButtonGroup-grouped:not(:last-of-type)': { + borderRight: '2px solid white', + }, + }} + > + V0 + V0.5 + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-coin-input.tsx b/infra/rooch-portal-v2/src/components/swap/swap-coin-input.tsx new file mode 100644 index 0000000000..7eab9288ff --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-coin-input.tsx @@ -0,0 +1,166 @@ +import { useDebounce } from 'react-use'; +import { useMemo, useState, useEffect } from 'react'; + +import { Stack, TextField } from '@mui/material'; + +import { toDust, fromDust, formatCoin, toBigNumber } from 'src/utils/number'; + +import { grey } from 'src/theme/core'; + +import Label from './typography/label'; +import SwapCoinSelectButton from './swap-coin-select-button'; + +import type { UserCoin, InteractiveMode } from './types'; + +export interface SwapCoinInputProps { + coins: UserCoin[]; + coin?: UserCoin; + type: InteractiveMode; + interactiveMode: InteractiveMode; + disabledCoins: string[]; + fixedSwap?: boolean; + hiddenValue?: boolean; + onChange: (coin: UserCoin, source: 'amount' | 'coin') => void; +} + +export default function SwapCoinInput({ + coins, + coin, + type, + interactiveMode, + disabledCoins, + fixedSwap, + hiddenValue, + onChange, +}: SwapCoinInputProps) { + const [value, setValue] = useState(''); + const [debouncedValue, setDebouncedValue] = useState(coin?.amount || 0n); + const [shouldUpdate, setShouldUpdate] = useState(false); + + useDebounce( + () => { + if (coin) { + try { + let temp = value; + const decimalIndex = value.indexOf('.'); + if (decimalIndex !== -1 && value.length - decimalIndex - 1 > coin.decimals) { + temp = value.substring(0, decimalIndex + coin.decimals + 1); + } + const amount = toDust(temp, coin.decimals); + setDebouncedValue(amount); + } catch (e) { +// toast.error(String(e)); + console.log(e) + } + } + }, + 300, + [value, coin] + ); + + useEffect(() => { + if (coin) { + setShouldUpdate(false); + setValue(fromDust(coin.amount, coin.decimals).decimalPlaces(coin.decimals).toString()); + } + }, [coin, coin?.amount]); + + useEffect(() => { + if (coin && shouldUpdate && toBigNumber(debouncedValue).gt(0)) { + onChange( + { + ...coin, + amount: debouncedValue, + }, + 'amount' + ); + } + }, [coin, debouncedValue, onChange, shouldUpdate]); + + const active = useMemo(() => type === interactiveMode, [type, interactiveMode]); + const coinUsd = useMemo(() => { + if (!coin) { + return 0; + } + return fromDust(coin.amount, coin.decimals).times(coin.price).decimalPlaces(2).toNumber(); + }, [coin]); + + return ( + + + + {coin && ( + + )} + + + + + { + setValue(e.target.value); + setShouldUpdate(true); + }} + placeholder="0.0" + type="text" + autoComplete="off" + inputProps={{ + inputMode: 'decimal', + autoCorrect: 'off', + pattern: '^[0-9]*[.,]?[0-9]*$', + spellCheck: 'false', + }} + sx={{ + flexGrow: 1, + '& .MuiInputBase-input': { + padding: '0', + fontSize: '1.25rem', + fontWeight: 600, + lineHeight: '24px', + color: grey[900], + }, + '& .MuiInputBase-input.Mui-disabled': { + WebkitTextFillColor: grey[900], + }, + '& fieldset': { + border: 'none', + }, + }} + /> + {!hiddenValue && ( + + + + )} + + onChange(coin, 'coin')} + /> + + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-coin-select-button.tsx b/infra/rooch-portal-v2/src/components/swap/swap-coin-select-button.tsx new file mode 100644 index 0000000000..6e7e2f1c34 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-coin-select-button.tsx @@ -0,0 +1,242 @@ +import type { DialogProps } from '@mui/material'; + +import { useState, useEffect } from 'react'; + +import { + Box, + List, + Stack, + Dialog, + darken, + styled, + Divider, + ListItem, + TextField, + Typography, + ListItemIcon, + ListItemText, + DialogContent, + InputAdornment, + ListItemButton, + ListItemSecondaryAction, +} from '@mui/material'; + +import { formatCoin, toBigNumber } from 'src/utils/number'; + +import { grey } from 'src/theme/core'; + +import Text from './typography/text'; +import { Iconify } from '../iconify'; + +import type { UserCoin } from './types'; + +export interface CoinSelectButtonProps { + coins: UserCoin[]; + coin?: UserCoin; + disabledCoins: string[]; + fixedSwap?: boolean; + onSelect: (coin: UserCoin) => void; +} + +export default function SwapCoinSelectButton({ + coins, + coin, + disabledCoins, + fixedSwap, + onSelect, +}: CoinSelectButtonProps) { + const [showModal, setShowModal] = useState(false); + const [search, setSearch] = useState(''); + const [filterCoins, setFilterCoins] = useState(coins); + + useEffect(() => { + if (search) { + setFilterCoins(coins.filter((it) => it.name.toLowerCase().includes(search.toLowerCase()))); + } else { + setFilterCoins(coins); + } + }, [search, coins]); + + return ( + + {fixedSwap ? ( + + {coin && } + {coin ? coin.symbol : 'Select Token'} + + ) : ( + { + setShowModal(true); + }} + sx={{ + width: '160px', + height: '48px', + padding: '12px', + borderRadius: '6px', + border: '1px solid #D0D5DD', + background: '#FFF', + boxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05)', + cursor: 'pointer', + '&:hover': { + background: darken('#FFF', 0.025), + }, + }} + > + {coin && } + {coin ? coin.symbol : 'Select Token'} + + + )} + + { + setShowModal(false); + }} + maxWidth="md" + > + + + + + ), + endAdornment: ( + { + setShowModal(false); + }} + sx={{ + cursor: 'pointer', + }} + > +
Esc
+
+ ), + }} + onChange={(e) => { + if (e.target.value.toLowerCase() === 'usdc') { + setSearch('usd coin'); + } else if (e.target.value.toLowerCase() === 'usdt') { + setSearch('tether usd'); + } else { + setSearch(e.target.value); + } + }} + /> + + + {filterCoins.map((coin, index) => ( + { + if (!disabledCoins.includes(coin.coinType)) { + onSelect(coin); + setSearch(''); + setShowModal(false); + } + }} + > + + + + + + {coin.symbol} + {coin.name} + + {toBigNumber(coin.balance).gt(0) && ( + + {formatCoin(coin, true)} + + )} + + + ))} + +
+
+
+ ); +} + +export const CoinSelectDialog = styled(Dialog)(() => ({ + img: { + width: '24px', + height: '24px', + }, + '& .MuiDialog-paper': { + width: '420px', + }, + '& .MuiDialogContent-root': { + padding: 0, + }, + '& .MuiListItemButton-root': { + padding: '12px 20px', + }, + '& .MuiListItemIcon-root': { + minWidth: '24px', + marginRight: '12px', + }, + '& .search fieldset': { + border: 'none', + }, + '& .name': { + fontWeight: 500, + fontSize: '1rem', + lineHeight: '24px', + color: grey[900], + }, + '& .desc': { + fontWeight: 500, + fontSize: '0.75rem', + lineHeight: '14px', + color: 'rgba(0, 0, 0, 0.35)', + }, + '& .amount': { + fontWeight: 500, + fontSize: '0.75rem', + lineHeight: '14px', + color: 'rgba(0, 0, 0, 0.35)', + }, + '& .esc-button': { + padding: '3px 8px', + background: '#fff', + border: `1px solid ${grey[300]}`, + borderRadius: '6px', + fontWeight: 500, + fontSize: '0.75rem', + lineHeight: '18px', + color: grey[700], + }, +})); diff --git a/infra/rooch-portal-v2/src/components/swap/swap-container.tsx b/infra/rooch-portal-v2/src/components/swap/swap-container.tsx new file mode 100644 index 0000000000..ad9afe7737 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-container.tsx @@ -0,0 +1,25 @@ +import type { ReactNode } from 'react'; +import type { SxProps } from '@mui/material'; + +import { Box, Container } from '@mui/material'; + +export interface SwapContainerProps { + width?: number; + sx?: SxProps; + children: ReactNode; +} + +export default function SwapContainer({ width = 520, sx, children }: SwapContainerProps) { + return ( + + + {children} + + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-details.tsx b/infra/rooch-portal-v2/src/components/swap/swap-details.tsx new file mode 100644 index 0000000000..7e43b56afd --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-details.tsx @@ -0,0 +1,328 @@ +import type { ReactNode } from 'react'; + +import { useMemo, useState } from 'react'; + +import { + Box, + Stack, + Divider, + Accordion, + Typography, + AccordionDetails, + AccordionSummary, + CircularProgress, +} from '@mui/material'; + +import { fNumber } from 'src/utils/format-number'; + +import { grey, error, success, warning } from 'src/theme/core'; + +import Text from './typography/text'; +import { Iconify } from '../iconify'; +import Label from './typography/label'; +import PoolVersionSelect from './pool-version-select'; +import { toBigNumber, formatCurrency, fromDustToPrecision } from '../../utils/number'; + +import type { SwapProps, PoolVersion, PriceImpactSeverity } from './types'; + +export default function SwapDetails({ + loading, + interactiveMode, + fromCoin, + toCoin, + swapAmount, + convertRate, + slippagePercent, + slippageAmount, + platformFeePercent, + platformFeeAmount, + priceImpact, + priceImpactSeverity, + canSelectCurve, + curve, + canSelectVersion, + version, + variant, + fixedSwap, + onVersionChange, +}: Omit< + SwapProps, + | 'coins' + | 'onSlippageChange' + | 'onCurveTypeChange' + | 'onVersionChange' + | 'getUsdEquivalent' + | 'onSwap' + | 'onSwitch' + | 'onPreview' + | 'onPropose' +> & { variant: 'propose' | 'transaction'; onVersionChange?: (version: PoolVersion) => void }) { + const [showDetails, setShowDetails] = useState(false); + + const targetToken = useMemo( + () => (interactiveMode === 'from' ? fromCoin : toCoin), + [interactiveMode, fromCoin, toCoin] + ); + + const header = useMemo(() => { + if (variant === 'propose') { + return ( + + 1 {fromCoin?.symbol} = {fNumber(toBigNumber(convertRate).toString())} {toCoin?.symbol}{' '} + {!fixedSwap && + `(including + fee)`} + + ); + } + return ( + + {interactiveMode === 'from' && !fixedSwap && ( + Expected Output} + right={ + + } + /> + )} + {interactiveMode === 'to' && ( + Expected Input} + right={ + + } + /> + )} + + ); + }, [ + variant, + interactiveMode, + fixedSwap, + swapAmount, + toCoin?.decimals, + toCoin?.symbol, + fromCoin?.decimals, + fromCoin?.symbol, + convertRate, + ]); + + return ( + + + + ) + } + onClick={() => { + if (fixedSwap) { + return; + } + setShowDetails(!showDetails); + }} + sx={{ + borderRadius: '8px 8px 0 0', + border: `1px solid ${grey[300]}`, + padding: '4px 16px', + }} + > + {loading ? : header} + + + {interactiveMode === 'from' && ( + + {variant === 'propose' && ( + + Estimated rate, the actual amount received depends on the rate at the time of + transaction confirmation block. + + } + right={ + fixedSwap ? null : ( + + ) + } + /> + )} + {!fixedSwap && ( + Minimum Received after Slippage ({(slippagePercent || 0) * 100} %) + } + right={ + + } + /> + )} + + )} + {interactiveMode === 'to' && ( + + {variant === 'propose' && ( + Expected Input} + right={ + + } + /> + )} + Maximum Send after Slippage ({(slippagePercent || 0) * 100} %)} + right={ + + } + /> + + )} + {showDetails && !fixedSwap && ( + <> + + + {variant === 'propose' && !fixedSwap && ( + Price Impact} + right={ + + } + /> + )} + + Platform Fee ({toBigNumber(platformFeePercent).times(100).toString()} %) + + } + right={ + + } + /> + {variant === 'propose' && !canSelectCurve && !fixedSwap && ( + Curve Type} right={} /> + )} + {variant === 'propose' && canSelectVersion && !fixedSwap && ( + Pool Version} + right={} + /> + )} + + + )} + + + + ); +} + +function DetailsItem({ left, right }: { left: ReactNode; right: ReactNode }) { + return ( + + {left} + {right} + + ); +} + +function PriceImpactLabel({ + priceImpact, + priceImpactSeverity, +}: { + priceImpact: number; + priceImpactSeverity: PriceImpactSeverity; +}) { + const color = useMemo(() => { + if (priceImpactSeverity === 'normal') { + return success[700]; + } + if (priceImpactSeverity === 'warning') { + return warning[500]; + } + return error[800]; + }, [priceImpactSeverity]); + + return ( + + alert + + {toBigNumber(priceImpact).toFixed(2)} % + + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-header.tsx b/infra/rooch-portal-v2/src/components/swap/swap-header.tsx new file mode 100644 index 0000000000..a97ba33bd1 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-header.tsx @@ -0,0 +1,197 @@ +import type { ReactNode } from 'react'; + +import { useMemo, useState } from 'react'; + +import { Box, Stack, Button, Popover, Tooltip, TextField, InputAdornment } from '@mui/material'; + +import { toBigNumber } from 'src/utils/number'; + +import { grey } from 'src/theme/core'; + +import Label from './typography/label'; +import Header from './typography/header'; +import { Iconify } from '../iconify/iconify'; + +export interface SwapWidgetHeaderProps { + slippage: number; + header?: ReactNode; + fixedSwap?: boolean; + onSlippageChange: (slippage: number) => void; +} + +export default function SwapHeader({ + slippage, + header = 'Purchase RGas', + fixedSwap, + onSlippageChange, +}: SwapWidgetHeaderProps) { + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + + const headerComponent = useMemo(() => { + if (typeof header === 'string') { + return ( + + +
{header}
+
+
+ ); + } + return header; + }, [header]); + + const slippageHint = useMemo(() => { + if (slippage < 0.005) { + return 'Your transaction may fail'; + } + if (slippage > 0.015) { + return 'Your transaction may be frontrun'; + } + return ''; + }, [slippage]); + + const displayValue = useMemo(() => toBigNumber(slippage).times(100).toFixed(3), [slippage]); + + return ( + + {headerComponent} + {!fixedSwap && ( + <> + { + setAnchorEl(e.currentTarget); + }} + /> + setAnchorEl(null)} + anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} + transformOrigin={{ vertical: 'top', horizontal: 'right' }} + sx={{ + '& .MuiPaper-root': { + width: '300px', + mt: '8px', + borderRadius: '6px', + border: '1px solid white', + boxShadow: '0px 4px 8px 0px rgba(0, 0, 0, 0.15)', + }, + '& .MuiList-root': { + padding: 0, + }, + }} + > + + + + setAnchorEl(null)} + /> + + + + + + + + + + + {[0.005, 0.01, 0.015].map((v) => ( + + ))} + + + % + + ), + }} + sx={{ + 'input::-webkit-outer-spin-button, input::-webkit-inner-spin-button': { + WebkitAppearance: 'none', + margin: 0, + }, + }} + onChange={(e) => { + const result = Number(e.target.value); + if (result) { + onSlippageChange(toBigNumber(result).div(100).toNumber()); + } + }} + /> + + + + + )} + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-hint-text.tsx b/infra/rooch-portal-v2/src/components/swap/swap-hint-text.tsx new file mode 100644 index 0000000000..0e97c72c13 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-hint-text.tsx @@ -0,0 +1,79 @@ +import { useMemo } from 'react'; + +import { Typography } from '@mui/material'; + +import { formatCoin } from 'src/utils/number'; + +import type { UserCoin, InteractiveMode } from './types'; + +export interface SwapHintTextProps { + fromCoin: UserCoin; + toCoin: UserCoin; + interactiveMode: InteractiveMode; + amount: number; +} + +export default function SwapHintText({ + fromCoin, + toCoin, + interactiveMode, + amount, +}: SwapHintTextProps) { + const hintText = useMemo(() => { + if (!amount) { + return null; + } + if (interactiveMode === 'from') { + return ( + + Output is estimated. You will receive at least{' '} + + {formatCoin(toCoin)} {toCoin.symbol} + {' '} + or the transaction will revert. + + ); + } + return ( + + Input is estimated. You will send at least{' '} + + {formatCoin(fromCoin)} {fromCoin.symbol} + {' '} + or the transaction will revert. + + ); + }, [interactiveMode, fromCoin, toCoin, amount]); + + return hintText; +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-info-card.tsx b/infra/rooch-portal-v2/src/components/swap/swap-info-card.tsx new file mode 100644 index 0000000000..17ab06cd0d --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-info-card.tsx @@ -0,0 +1,151 @@ +import { useMemo } from 'react'; + +import { Box, CircularProgress, Stack, Typography } from '@mui/material'; + +import { grey, secondary } from 'src/theme/core'; +import swapDownIcon from '@/assets/swap/swap-down.svg'; + +import Label from './typography/label'; +import { formatCoin } from '../../utils/number'; + +import type { UserCoin, InteractiveMode } from './types'; + +export interface SwapInfoCardProps { + fromCoin: UserCoin; + toCoin: UserCoin; + interactiveMode: InteractiveMode; + type?: 'propose' | 'pending' | 'history'; + loading?: boolean; +} + +export default function SwapInfoCard({ + fromCoin, + toCoin, + interactiveMode, + type = 'propose', + loading, +}: SwapInfoCardProps) { + return ( + + + + + + + + ); +} + +function SwapItem({ + coin, + interactiveMode, + type, + variant, + loading, +}: { + coin: UserCoin; + interactiveMode: InteractiveMode; + type: 'from' | 'to'; + variant: 'propose' | 'pending' | 'history'; + loading?: boolean; +}) { + const bgColor = useMemo(() => { + if (variant === 'propose') { + return interactiveMode === type ? '#FCFDFD' : '#F1F5F5'; + } + return '#FFF'; + }, [interactiveMode, type, variant]); + + const imageSize = useMemo(() => (variant === 'propose' ? '32px' : '24px'), [variant]); + + const border = useMemo( + () => (variant === 'propose' ? '1px solid #F1F5F5' : '1px solid #E2E4E9'), + [variant] + ); + + const label = useMemo(() => { + if (variant === 'propose' || variant === 'history') { + return type.toUpperCase(); + } + return interactiveMode === type ? type.toUpperCase() : `${type.toUpperCase()} (OBSERVED)`; + }, [variant, interactiveMode, type]); + + return ( + + + + {loading ? ( + + ) : ( + + {formatCoin(coin)} + + )} + {!loading && ( + + + + {coin.symbol} + + + )} + + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-switch-icon.tsx b/infra/rooch-portal-v2/src/components/swap/swap-switch-icon.tsx new file mode 100644 index 0000000000..452275296a --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-switch-icon.tsx @@ -0,0 +1,38 @@ +import { Box } from '@mui/material'; + +import { secondary } from 'src/theme/core'; + +export interface SwapSwitchIconProps { + onClick?: () => void; +} + +export default function SwapSwitchIcon({ onClick }: SwapSwitchIconProps) { + return ( + + + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-transaction-header.tsx b/infra/rooch-portal-v2/src/components/swap/swap-transaction-header.tsx new file mode 100644 index 0000000000..0db8dd4cec --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-transaction-header.tsx @@ -0,0 +1,48 @@ + + + + + +import { Box, Stack, Typography } from '@mui/material'; + +import { grey } from 'src/theme/core'; +import headerIcon from '@/assets/swap/swap-header-icon.svg'; + +export default function SwapTransactionHeader({ invert = false }: { invert?: boolean }) { + return ( + + {invert && ( + + )} + {!invert && ( + + )} + + Swap + + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap-transaction-info-card.tsx b/infra/rooch-portal-v2/src/components/swap/swap-transaction-info-card.tsx new file mode 100644 index 0000000000..0f80821493 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap-transaction-info-card.tsx @@ -0,0 +1,37 @@ +import { Box } from '@mui/material'; + +import { grey } from 'src/theme/core'; + +import SwapInfoCard from './swap-info-card'; + +import type { SwapInfoCardProps } from './swap-info-card'; + +export interface SwapTransactionInfoCardProps extends SwapInfoCardProps { + type: 'pending' | 'history'; +} + +export default function SwapTransactionInfoCard({ + fromCoin, + toCoin, + interactiveMode, + loading, + type, +}: SwapTransactionInfoCardProps) { + return ( + + + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/swap.tsx b/infra/rooch-portal-v2/src/components/swap/swap.tsx new file mode 100644 index 0000000000..4bf035e5fd --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/swap.tsx @@ -0,0 +1,271 @@ +import { useMemo } from 'react'; + +import { LoadingButton } from '@mui/lab'; +import { Alert, Stack, darken, CircularProgress } from '@mui/material'; + +import { grey, secondary } from 'src/theme/core'; + +import SwapHeader from './swap-header'; +import SwapDetails from './swap-details'; +import { DEFAULT_SLIPPAGE } from './types'; +import SwapCoinInput from './swap-coin-input'; +// import SwapPreviewModal from './swap-preview-modal'; +import SwapSwitchIcon from './swap-switch-icon'; +import CurveTypeSelect from './curve-type-select'; + +import type { SwapProps } from './types'; + +export default function Swap({ + loading, + coins, + fromCoin, + toCoin, + interactiveMode, + canSelectCurve, + swapAmount, + convertRate, + slippagePercent = DEFAULT_SLIPPAGE, + slippageAmount, + platformFeePercent, + platformFeeAmount, + priceImpact, + priceImpactSeverity, + curve, + warning, + validationError, + canSelectVersion, + version, + fixedSwap, + hiddenValue, + txHash, + gasInfo, + simulationStatus, + simulationError, + proposing, + onSlippageChange, + onCurveTypeChange, + onVersionChange, + onSwitch, + onSwap, + onPreview, + onPropose, +}: SwapProps) { + const disabledCoins: string[] = useMemo( + () => [fromCoin?.coinType || '', toCoin?.coinType || ''], + [fromCoin?.coinType, toCoin?.coinType] + ); + + const showDetails = useMemo( + () => + !!( + fromCoin?.coinType && + fromCoin?.amount && + toCoin?.coinType && + toCoin?.amount && + interactiveMode + ), + [fromCoin?.coinType, fromCoin?.amount, toCoin?.coinType, toCoin?.amount, interactiveMode] + ); + + const proposeButtonContent: { text: string; disabled?: boolean } = useMemo(() => { + if (validationError) { + return { + text: validationError, + disabled: true, + }; + } + + if ((fromCoin?.amount || 0) > (fromCoin?.balance || 0)) { + return { + text: 'Insufficient balance', + disabled: true, + }; + } + + if (slippagePercent <= 0 || slippagePercent > 0.5) { + return { + text: 'Invalid slippage', + disabled: true, + }; + } + + if (showDetails) { + return { + text: 'Submit', + }; + } + return { + text: 'Submit', + disabled: true, + }; + }, [validationError, fromCoin?.amount, fromCoin?.balance, slippagePercent, showDetails]); + + const sortedBalanceCoins = useMemo( + () => + coins.sort((a, b) => { + if (a.balance === 0n) { + return 1; + } + return -1; + }), + [coins] + ); + + return ( + + + + + { + onSwap({ + fromCoin: coin, + toCoin, + interactiveMode: source === 'amount' ? 'from' : 'to', + }); + }} + /> + + { + await onSwap({ + fromCoin, + toCoin: coin, + interactiveMode: source === 'amount' ? 'to' : 'from', + }); + }} + /> + + + {warning && + (typeof warning === 'string' ? ( + + {warning} + + ) : ( + warning + ))} + + {canSelectCurve && curve && ( + + )} + {showDetails && ( + + )} + { + onPreview(); + }} + > + {proposeButtonContent.text} + + {txHash && ( + + + Transaction has been submitted, awaiting confirmation + + + + check in the{' '} + + mempool.space + + + + )} + + {/* setOpenPreview(false)} + fromCoin={fromCoin} + toCoin={toCoin} + interactiveMode={interactiveMode} + swapAmount={swapAmount} + slippagePercent={slippagePercent} + slippageAmount={slippageAmount} + platformFeePercent={platformFeePercent} + platformFeeAmount={platformFeeAmount} + convertRate={convertRate} + priceImpact={priceImpact} + priceImpactSeverity={priceImpactSeverity} + canSelectCurve={canSelectCurve} + curve={curve} + canSelectVersion={canSelectVersion} + version={version} + gasInfo={gasInfo} + simulationStatus={simulationStatus} + simulationError={simulationError} + proposing={proposing} + onPropose={onPropose} + /> */} + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/types.ts b/infra/rooch-portal-v2/src/components/swap/types.ts new file mode 100644 index 0000000000..d05d7afe95 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/types.ts @@ -0,0 +1,192 @@ +import type { ReactNode } from 'react'; + +export const DEFAULT_SLIPPAGE = 0.005; +export const VERSION_0 = 0; +export const VERSION_0_5 = 0.5; + +export type SimulationStatus = 'new' | 'simulating' | 'success' | 'error'; + +/** + * Common coin info type + */ +export interface Coin { + coinType: string; + decimals: number; + name: string; + symbol: string; + icon: string; + balance: bigint; + price: number; +} + +export interface UserCoin extends Coin { + amount: bigint; +} + +export type InteractiveMode = 'from' | 'to'; + +export type CurveType = 'stable' | 'uncorrelated'; + +export type PriceImpactSeverity = 'normal' | 'warning' | 'alert'; + +export type PoolVersion = typeof VERSION_0 | typeof VERSION_0_5; + +export interface SwapProps { + fixedSwap?: boolean; + hiddenValue?: boolean; + txHash?: string; + /** + * Current supported token list + */ + coins: UserCoin[]; + + /** + * General loading status + */ + loading?: boolean; + + /** + * Current from currency + */ + fromCoin?: UserCoin; + + /** + * Current to currency + */ + toCoin?: UserCoin; + + /** + * Swap direction + */ + interactiveMode: InteractiveMode; + + /** + * Target swap amount + */ + swapAmount?: bigint; + + /** + * Slippage percentage + */ + slippagePercent?: number; + + /** + * Slippage amount + */ + slippageAmount?: number; + + /** + * Boolean flag indicating whether current pool exists or not + */ + isPoolExist?: boolean; + + /** + * Convert rate between from and to currency + */ + convertRate?: number; + + /** + * Platform fee percent + */ + platformFeePercent?: number; + + /** + * Platform fee amount + */ + platformFeeAmount?: number; + + /** + * Price impact percentage + */ + priceImpact?: number; + + /** + * Price impact severity + */ + priceImpactSeverity?: PriceImpactSeverity; + + /** + * Can select curve type + */ + canSelectCurve?: boolean; + + /** + * Swap curve type + */ + curve?: CurveType; + + /** + * Can select pool contract version + */ + canSelectVersion?: boolean; + + /** + * Contract version + */ + version?: PoolVersion; + + /** + * Swap error message + */ + warning?: ReactNode; + + /** + * Disable propose button and display error text + */ + validationError?: string; + + /** + * Gas info + */ + gasInfo?: ReactNode; + + simulationStatus?: SimulationStatus; + simulationError?: string; + proposing?: boolean; + + /** + * Callback for slippage change + * @param slippage slippage + * @returns + */ + onSlippageChange: (slippage: number) => void; + + /** + * Callback for curve type change + * @param curveType curve type + * @returns + */ + onCurveTypeChange: (curveType: CurveType) => void; + + /** + * Callback for version change + * @param version pool contract version + * @returns + */ + onVersionChange: (version: PoolVersion) => void; + + /** + * On switch token + * @returns + */ + onSwitch?: () => void; + + /** + * On swap parameter change + * @param payload swap payload + * @returns + */ + onSwap: (payload: Pick) => Promise; + + /** + * On preview modal open + * @returns + */ + onPreview: () => Promise; + + /** + * On propose event + * @returns + */ + onPropose: () => Promise; +} diff --git a/infra/rooch-portal-v2/src/components/swap/typography/header.tsx b/infra/rooch-portal-v2/src/components/swap/typography/header.tsx new file mode 100644 index 0000000000..aeab58d684 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/typography/header.tsx @@ -0,0 +1,19 @@ +import type { TypographyProps } from '@mui/material'; + +import { Typography } from '@mui/material'; + +export default function Header({ sx, children }: TypographyProps) { + return ( + + {children} + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/typography/label.tsx b/infra/rooch-portal-v2/src/components/swap/typography/label.tsx new file mode 100644 index 0000000000..0fafb9d7c3 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/typography/label.tsx @@ -0,0 +1,20 @@ +import type { TypographyProps } from '@mui/material'; + +import { Typography } from '@mui/material'; + +export default function Label({ sx, children, onClick }: TypographyProps) { + return ( + + {children} + + ); +} diff --git a/infra/rooch-portal-v2/src/components/swap/typography/text.tsx b/infra/rooch-portal-v2/src/components/swap/typography/text.tsx new file mode 100644 index 0000000000..08f03b44d3 --- /dev/null +++ b/infra/rooch-portal-v2/src/components/swap/typography/text.tsx @@ -0,0 +1,19 @@ +import type { TypographyProps } from '@mui/material'; + +import { Typography } from '@mui/material'; + +export default function Text({ sx, children, className }: TypographyProps) { + return ( + + {children} + + ); +} diff --git a/infra/rooch-portal-v2/src/hooks/use-networks.ts b/infra/rooch-portal-v2/src/hooks/use-networks.ts index 8004866df0..ca783ca924 100644 --- a/infra/rooch-portal-v2/src/hooks/use-networks.ts +++ b/infra/rooch-portal-v2/src/hooks/use-networks.ts @@ -13,11 +13,20 @@ console.log( ); const { networkConfig, useNetworkVariable, useNetworkVariables } = createNetworkConfig({ + mainnet: { + url: getRoochNodeUrl('mainnet'), + variables: { + roochOperatingAddress: ROOCH_NFT_OPERATING_ADDRESS, + mintAddress: ROOCH_MINT_OPERATING_ADDRESS, + btcGasAddress: 'bc1prcajaj9n7e29u4dfp33x3hcf52yqeegspdpcd79pqu4fpr6llx4sugkfjt' + }, + }, testnet: { url: getRoochNodeUrl('testnet'), variables: { roochOperatingAddress: ROOCH_NFT_OPERATING_ADDRESS, mintAddress: ROOCH_MINT_OPERATING_ADDRESS, + btcGasAddress: 'tb1prcajaj9n7e29u4dfp33x3hcf52yqeegspdpcd79pqu4fpr6llx4stqqxgy' }, }, localnet: { @@ -25,6 +34,7 @@ const { networkConfig, useNetworkVariable, useNetworkVariables } = createNetwork variables: { roochOperatingAddress: ROOCH_NFT_OPERATING_ADDRESS, mintAddress: ROOCH_MINT_OPERATING_ADDRESS, + btcGasAddress: 'tb1prcajaj9n7e29u4dfp33x3hcf52yqeegspdpcd79pqu4fpr6llx4stqqxgy' }, }, }); diff --git a/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx b/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx index eb336efdb8..deb9fa2c95 100644 --- a/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx +++ b/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx @@ -2,6 +2,8 @@ import { paths } from 'src/routes/paths'; import { Iconify } from 'src/components/iconify'; +import { isMainNetwork } from '../utils/env' + export const navData = [ /** * My Account @@ -24,6 +26,12 @@ export const navData = [ path: paths.dashboard.transactions, icon: , }, + { + title: 'Purchase Gas', + path: paths.dashboard['gas-swap'], + icon: , + noAddressRequired: true, + }, { title: 'Settings', path: paths.dashboard.settings, @@ -65,6 +73,12 @@ export const navData = [ icon: , noAddressRequired: true, }, + { + title: isMainNetwork() ? "Testnet" : "MainNet", + path: isMainNetwork() ? "https://test.portal.rooch.network" : "https://portal.rooch.network", + icon: , + noAddressRequired: true, + }, ], }, -]; +].filter((item) => !(isMainNetwork() && item.subheader === 'Tokens')); diff --git a/infra/rooch-portal-v2/src/layouts/dashboard/layout.tsx b/infra/rooch-portal-v2/src/layouts/dashboard/layout.tsx index b886db17bb..c57d268ae5 100644 --- a/infra/rooch-portal-v2/src/layouts/dashboard/layout.tsx +++ b/infra/rooch-portal-v2/src/layouts/dashboard/layout.tsx @@ -20,10 +20,10 @@ import { useSettingsContext } from 'src/components/settings'; import { Main } from './main'; import { NavMobile } from './nav-mobile'; import { layoutClasses } from '../classes'; +import { NavVertical } from './nav-vertical'; import { HeaderBase } from '../core/header-base'; import { LayoutSection } from '../core/layout-section'; import { navData as dashboardNavData } from '../config-nav-dashboard'; -import { NavVertical } from './nav-vertical'; export type DashboardLayoutProps = { sx?: SxProps; @@ -119,18 +119,20 @@ export function DashboardLayout({ sx, children, data }: DashboardLayoutProps) { }} /> } - sidebarSection={ - settings.onUpdateField( - 'navLayout', - settings.navLayout === 'vertical' ? 'mini' : 'vertical' - ) - } - />} + sidebarSection={ + + settings.onUpdateField( + 'navLayout', + settings.navLayout === 'vertical' ? 'mini' : 'vertical' + ) + } + /> + } footerSection={null} cssVars={{ ...navColorVars.layout, diff --git a/infra/rooch-portal-v2/src/middleware.ts b/infra/rooch-portal-v2/src/middleware.ts index 9359a6201a..c4799b2113 100644 --- a/infra/rooch-portal-v2/src/middleware.ts +++ b/infra/rooch-portal-v2/src/middleware.ts @@ -1,12 +1,14 @@ -import { NextRequest, NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +import { NextResponse } from 'next/server'; +import { getRoochNodeUrl } from '@roochnetwork/rooch-sdk'; const iconDomains = [ 'https://api.unisvg.com', 'https://api.iconify.design', 'https://api.simplesvg.com', ]; -const apiDomains = ['https://dev-seed.rooch.network', 'https://test-seed.rooch.network']; - +const apiDomains = [getRoochNodeUrl('mainnet'), getRoochNodeUrl('testnet')]; const isProduction = process.env.NODE_ENV === 'production'; export function middleware(request: NextRequest) { @@ -24,7 +26,7 @@ export function middleware(request: NextRequest) { name: 'style-src', values: ["'self'", "'unsafe-inline'"], }, - { name: 'img-src', values: ["'self'", 'data:', 'blob:'] }, + { name: 'img-src', values: ["'self'", 'data:', 'blob:', 'https:'] }, { name: 'font-src', values: ["'self'", 'data:'] }, { name: 'object-src', values: ["'none'"] }, { name: 'base-uri', values: ["'self'"] }, diff --git a/infra/rooch-portal-v2/src/routes/paths.ts b/infra/rooch-portal-v2/src/routes/paths.ts index 8b7204426e..02a06a8ead 100644 --- a/infra/rooch-portal-v2/src/routes/paths.ts +++ b/infra/rooch-portal-v2/src/routes/paths.ts @@ -12,6 +12,6 @@ export const paths = { apps: `${ROOTS.DASHBOARD}/apps`, settings: `${ROOTS.DASHBOARD}/settings`, search: `${ROOTS.DASHBOARD}/search`, - redEnvelope: `${ROOTS.DASHBOARD}/red-envelope/detail`, + 'gas-swap': `${ROOTS.DASHBOARD}/gas-swap`, }, }; diff --git a/infra/rooch-portal-v2/src/sections/assets/components/ordinal-list-card.tsx b/infra/rooch-portal-v2/src/sections/assets/components/ordinal-list-card.tsx index d56597ed67..aafcc91dc7 100644 --- a/infra/rooch-portal-v2/src/sections/assets/components/ordinal-list-card.tsx +++ b/infra/rooch-portal-v2/src/sections/assets/components/ordinal-list-card.tsx @@ -1,11 +1,12 @@ import type { ReactNode } from 'react'; import type { IndexerStateIDView } from '@roochnetwork/rooch-sdk'; +import DOMPurify from 'dompurify'; import { useRef, useMemo, useState } from 'react'; import { useRoochClientQuery } from '@roochnetwork/rooch-sdk-kit'; import { Box, Card, Chip, Skeleton, CardHeader, Typography, CardContent } from '@mui/material'; -import DOMPurify from 'dompurify'; + import { hexToString } from 'src/utils/common'; import { EmptyContent } from 'src/components/empty-content/empty-content'; diff --git a/infra/rooch-portal-v2/src/sections/assets/components/utxo-list-card.tsx b/infra/rooch-portal-v2/src/sections/assets/components/utxo-list-card.tsx index 117dd3b9d5..9013a35246 100644 --- a/infra/rooch-portal-v2/src/sections/assets/components/utxo-list-card.tsx +++ b/infra/rooch-portal-v2/src/sections/assets/components/utxo-list-card.tsx @@ -5,6 +5,7 @@ import { useRoochClientQuery } from '@roochnetwork/rooch-sdk-kit'; import { Box, Card, Skeleton, CardHeader, CardContent } from '@mui/material'; +import { shortAddress } from 'src/utils/address'; import { fNumber } from 'src/utils/format-number'; import { EmptyContent } from 'src/components/empty-content'; @@ -54,14 +55,20 @@ export default function UTXOList({ address }: { address: string }) { } > {isUTXOPending ? ( - Array.from({ length: 4 }).map((i,index) => ) + Array.from({ length: 4 }).map((i, index) => ) ) : utxoList?.data.length === 0 ? ( ) : ( utxoList?.data.map((i) => ( - - Sats {fNumber(i.value?.value)} + + UTXO {shortAddress(i.id, 6, 4)} + + } + /> + {fNumber(i.value?.value)} Sats )) )} diff --git a/infra/rooch-portal-v2/src/sections/gas-swap/index.tsx b/infra/rooch-portal-v2/src/sections/gas-swap/index.tsx new file mode 100644 index 0000000000..5abd8e60c2 --- /dev/null +++ b/infra/rooch-portal-v2/src/sections/gas-swap/index.tsx @@ -0,0 +1,157 @@ +'use client'; + +import type { ReactNode } from 'react'; +import type { CurveType, PoolVersion, InteractiveMode } from 'src/components/swap/types'; + +import BigNumber from 'bignumber.js'; +import { useState, useEffect } from 'react'; +import { Args } from '@roochnetwork/rooch-sdk'; +import { useRoochClient, useCurrentWallet, useCurrentAddress } from '@roochnetwork/rooch-sdk-kit'; + +import { Stack } from '@mui/material'; + +import Swap from 'src/components/swap/swap'; +import { toast } from 'src/components/snackbar'; + +import { useNetworkVariable } from '../../hooks/use-networks' + +const swapCoins = [ + { + coinType: 'btc', + decimals: 8, + symbol: 'BTC', + name: 'BTC Coin', + icon: 'https://s2.coinmarketcap.com/static/img/coins/64x64/1.png', + price: 0, + }, + { + coinType: 'rgas', + decimals: 8, + symbol: 'RGas', + name: 'Rooch Gas', + icon: '/logo/logo-square.svg', + price: 0, + }, +]; + +export default function GasSwapOverview() { + const btcGasAddress = useNetworkVariable("btcGasAddress") + const [loading, setLoading] = useState(false); + const [submitting, setSubmitting] = useState(false); + const [btcBalance, setBtcBalance] = useState(0n); + const [rGasBalance, setRGasBalance] = useState(0n); + const [interactiveMode, setInteractiveMode] = useState('from'); + const [curve, setCurve] = useState('uncorrelated'); + const [warning, setWarning] = useState(); + const [convertRate, setConvertRate] = useState(); + const [platformFeePercent] = useState(0.003); + const [version, setVersion] = useState(0); + + const [fromSwapAmount, setFromSwapAmount] = useState(0n); + const [toSwapAmount, setToSwapAmount] = useState(0n); + const [txHash, setTxHash] = useState(); + + const address = useCurrentAddress(); + const wallet = useCurrentWallet(); + const client = useRoochClient(); + + useEffect(() => { + async function getBTCBalance() { + const res = await wallet.wallet?.getBalance(); + if (res) { + setBtcBalance(BigInt(res.confirmed)); + } + } + async function getRGasBalance() { + if (!address) { + return; + } + const res = await client.getBalance({ + owner: address?.genRoochAddress().toStr(), + coinType: '0x3::gas_coin::RGas', + }); + if (res) { + setRGasBalance(BigInt(res.balance)); + } + } + getBTCBalance(); + getRGasBalance(); + }, [wallet, address, client]); + + useEffect(() => { + async function fetchRate() { + try { + setLoading(true); + const res = await client.executeViewFunction({ + address: '0x872502737008ac71c4c008bb3846a688bfd9fa54c6724089ea51b72f813dc71e', + module: 'gas_market', + function: 'btc_to_rgas', + args: [Args.u64(fromSwapAmount)], + }); + setToSwapAmount(BigInt(Number(res.return_values?.[0]?.decoded_value || 0)) || 0n); + setConvertRate( + new BigNumber(Number(res.return_values?.[0]?.decoded_value || 0)) + .div(fromSwapAmount.toString()) + .toNumber() + ); + } catch (error) { + toast.error(String(error)); + } finally { + setLoading(false); + } + } + fetchRate(); + }, [client, fromSwapAmount]); + + return ( + + + {}} + onCurveTypeChange={(curveType: CurveType) => setCurve(curveType)} + onVersionChange={(version: PoolVersion) => setVersion(version)} + onSwap={async (payload) => { + const { fromCoin, toCoin, interactiveMode } = payload; + if (!fromCoin || !toCoin) { + return; + } + setFromSwapAmount(fromCoin.amount); + setInteractiveMode(interactiveMode); + }} + onPreview={async () => { + try { + setSubmitting(true); + const txHash = await wallet.wallet?.sendBtc({ + toAddress: btcGasAddress, + satoshis: Number(fromSwapAmount.toString()), + }); + setTxHash(txHash); + } catch (error) { + toast.error(String(error.message)); + } finally { + setSubmitting(false); + } + }} + onPropose={async () => {}} + /> + + + ); +} diff --git a/infra/rooch-portal-v2/src/sections/mint/components/mint-table-card.tsx b/infra/rooch-portal-v2/src/sections/mint/components/mint-table-card.tsx index d68690e890..a8147c2bf4 100644 --- a/infra/rooch-portal-v2/src/sections/mint/components/mint-table-card.tsx +++ b/infra/rooch-portal-v2/src/sections/mint/components/mint-table-card.tsx @@ -113,7 +113,6 @@ export default function MintTableCard({ const [isLoading, setIsLoading] = useState(!isStaticData); useEffect(() => { - console.log('🚀 ~ file: mint-table-card.tsx:117 ~ useEffect ~ isStaticData:', isStaticData); if (isStaticData || tokenList.length !== 0) { return; } diff --git a/infra/rooch-portal-v2/src/sections/red-envelope/detail/view.tsx b/infra/rooch-portal-v2/src/sections/red-envelope/detail/view.tsx index 87dbfccb0e..c803f2774d 100644 --- a/infra/rooch-portal-v2/src/sections/red-envelope/detail/view.tsx +++ b/infra/rooch-portal-v2/src/sections/red-envelope/detail/view.tsx @@ -45,7 +45,6 @@ export default function RedEnvelopeDetail({ redEnvelopeId }: { redEnvelopeId: st }, { refetchInterval: 5000 } ); - console.log('🚀 ~ file: view.tsx:21 ~ RedEnvelopeDetail ~ data:', redEnvelopeObject); const redEnvelopeInfo = useMemo(() => { const info = redEnvelopeObject?.data?.[0]?.decoded_value?.value as unknown as @@ -150,8 +149,6 @@ export default function RedEnvelopeDetail({ redEnvelopeId }: { redEnvelopeId: st }), ], }); - // const res = await signAndExecuteTransaction({ transaction: txn }); - // console.log('🚀 ~ file: view.tsx:160 ~ onClick={ ~ res:', res); const reward = await roochClient.getEvents({ eventHandleType: '0x1d6f6657fc996008a1e43b8c13805e969a091560d4cea57b1db9f3ce4450d977::red_envelope_v3::ClaimCoinEvent', @@ -159,7 +156,6 @@ export default function RedEnvelopeDetail({ redEnvelopeId }: { redEnvelopeId: st decode: true, }, }); - console.log('🚀 ~ file: view.tsx:167 ~ onClick={ ~ reward:', reward); }} > Claim diff --git a/infra/rooch-portal-v2/src/sections/tx/view.tsx b/infra/rooch-portal-v2/src/sections/tx/view.tsx index 62b99f9124..a5dfae7fcc 100644 --- a/infra/rooch-portal-v2/src/sections/tx/view.tsx +++ b/infra/rooch-portal-v2/src/sections/tx/view.tsx @@ -69,7 +69,6 @@ export function TxView({ hash }: { hash: string }) { tx_hashes: [hash], }, }); - console.log('🚀 ~ file: view.tsx:22 ~ TxView ~ transactionDetail:', transactionDetail?.data[0]); const txDetail = useMemo(() => transactionDetail?.data[0], [transactionDetail]); diff --git a/infra/rooch-portal-v2/src/utils/common.ts b/infra/rooch-portal-v2/src/utils/common.ts index 1aa9c1ec7d..958d1f8177 100644 --- a/infra/rooch-portal-v2/src/utils/common.ts +++ b/infra/rooch-portal-v2/src/utils/common.ts @@ -3,6 +3,10 @@ export const isSessionExpired = (lastActiveTime: number, maxInactiveInterval: nu return Date.now() > expirationTime; }; +export function sleep(time: number) { + return new Promise((resolve) => setTimeout(resolve, time)); +} + export const hexToString = (hex: string): string => { if (hex.startsWith('0x')) { hex = hex.substring(2); diff --git a/infra/rooch-portal-v2/src/utils/env.ts b/infra/rooch-portal-v2/src/utils/env.ts new file mode 100644 index 0000000000..1c836c64b5 --- /dev/null +++ b/infra/rooch-portal-v2/src/utils/env.ts @@ -0,0 +1,3 @@ +export function isMainNetwork() { + return window.location.hostname === 'https://portal.rooch.network'; +} diff --git a/infra/rooch-portal-v2/src/utils/number.ts b/infra/rooch-portal-v2/src/utils/number.ts new file mode 100644 index 0000000000..2eefd531c8 --- /dev/null +++ b/infra/rooch-portal-v2/src/utils/number.ts @@ -0,0 +1,164 @@ +import type { UserCoin } from 'src/components/swap/types'; + +import numeral from 'numeral'; +import { BigNumber } from 'bignumber.js'; + +export function decimalsMultiplier(decimals?: BigNumber.Value) { + return toBigNumber(10).pow(toBigNumber(decimals).abs()); +} + +export function formatCoinAmount(amount: number, decimals: number): string { + return toBigNumber(amount).div(decimalsMultiplier(decimals)).toFixed(decimals).toString(); +} + +export const splitValue = (value: string) => { + const spiltValue_ = String(value).split('.'); + const decimalLength = spiltValue_[1] && spiltValue_[1].length; + return { + spiltValue_, + lastIndex: Number(decimalLength) - 1, + }; +}; + +export function formatCurrency(amount: BigNumber.Value, decimals: number, suffix?: string) { + let value = +(amount || 0) / 10 ** decimals; + let fixed = decimals; + let prefix = ''; + + if (value > 10) { + fixed = 2; + } else if (value >= 1) { + fixed = 4; + } else if (value >= 0.1) { + fixed = 6; + } + + if (value === 0) { + fixed = 0; + } else if (value < 1 / 10 ** decimals) { + fixed = decimals; + value = +Number(1 / 10 ** decimals); + prefix = '~'; + } + + fixed = fixed > decimals ? decimals : fixed; + + const formatter = Intl.NumberFormat('en', { + notation: 'standard', + minimumFractionDigits: fixed, + maximumFractionDigits: fixed, + }); + + return prefix + cutTrailingZerosFromString(formatter.format(value)); +} + +export function cutTrailingZerosFromString(numberAsString: string) { + if (numberAsString.length === 1) return numberAsString; + const arr = numberAsString.match(/^-?(((\d{1,3}),?)+\.*?)*?\d*?(?=\.?0*$)/) || ['']; + return arr[0]; +} + +BigNumber.config({ + EXPONENTIAL_AT: 1e9, +}); + +export function toDust(val: BigNumber | number | string, decimal: number | bigint): bigint { + return bigNumberToBigInt(toDustBigNumber(val, decimal)); +} + +export function fromDust( + val: BigNumber | bigint | number | string, + decimal: number | bigint +): BigNumber { + return toBigNumber(val).div(new BigNumber(10).pow(decimal.toString())); +} + +function toDustBigNumber(val: BigNumber | number | string, decimal: number | bigint): BigNumber { + return toBigNumber(val).times(new BigNumber(10).pow(decimal.toString())); +} + +export function bigNumberToBigInt(val: BigNumber | number | string): bigint { + const str = toBigNumber(val).toString(); + return BigInt(str); +} + +export function bigIntToBigNumber(val: bigint) { + return BigNumber(val.toString()); +} + +export function fromDustToPrecision( + val: BigNumber | bigint | number | string, + decimal: number | bigint +): string { + BigNumber.config({ EXPONENTIAL_AT: 1e9 }); + const real = toBigNumber(val).div(new BigNumber(10).pow(decimal.toString())); + // <1 + if (real.isLessThan(1)) { + return real.toPrecision(3).replace(/\.?0+$/, ''); + // >=1 && <1,000,000 + } + if (real.isGreaterThanOrEqualTo(1) && real.isLessThan(1000000)) { + return real.toFixed(2); + // >1,000,000 + } + return real.toFixed(0); +} + +export function formatCoin(coin: UserCoin, useBalance?: boolean) { + return fromDustToPrecision(useBalance ? coin.balance : coin.amount, coin.decimals); +} + +/** + * Format value with given config + * + * ```ts + * numberDecimalSeparator(500000) // '500,000' + * ``` + * + * @param val format value. + */ +export function numberDecimalSeparator( + val: BigNumber | bigint | number | string, + groupSeparator?: string, + decimalSeparator?: string +) { + return BigNumber(val.toString()) + .toFormat({ + groupSize: 3, + groupSeparator: groupSeparator ?? ',', + decimalSeparator: decimalSeparator ?? '.', + }) + .toString(); +} + +export function toBigNumber( + val?: BigNumber | bigint | number | string | BigNumber.Instance +): BigNumber { + if (val instanceof BigNumber || (BigNumber.isBigNumber(val) && typeof val === 'object')) { + return val; + } + if (typeof val === 'number' || typeof val === 'string') { + return BigNumber(val); + } + if (typeof val === 'bigint') { + return bigIntToBigNumber(val); + } + if (typeof val === 'undefined') { + return BigNumber(0); + } + return BigNumber(val); +} + +export function currencyNumberFormatter(val: string | number | bigint) { + const bn = new BigNumber(val.toString()); + const formatStringWithLessThanOne = '0.[000000000000000000]'; + const formatStringWithGreaterThanM = '0.00 a'; + const formatString = '0,0.00'; + if (bn.isLessThan(1)) { + return numeral(bn.toNumber().toPrecision(3)).format(formatStringWithLessThanOne); + } + if (bn.isGreaterThanOrEqualTo(1e6)) { + return numeral(bn.toNumber()).format(formatStringWithGreaterThanM); + } + return numeral(bn.toNumber()).format(formatString); +} diff --git a/kube/mainnet/faucet/mainnet-faucet-deployment.yaml b/kube/mainnet/faucet/mainnet-faucet-deployment.yaml new file mode 100644 index 0000000000..0a479e03c8 --- /dev/null +++ b/kube/mainnet/faucet/mainnet-faucet-deployment.yaml @@ -0,0 +1,82 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mainnet-faucet + namespace: mainnet +spec: + replicas: 1 + selector: + matchLabels: + app: mainnet-faucet + template: + metadata: + labels: + app: mainnet-faucet + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias main + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-mainnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-faucet + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "faucet" + - "server" + - "--faucet-sender" + # the first account + - "rooch1ps458n8n37rzz3vtseu8unvkzf37udant9d4xhudsu5tv4zpzz4s30nlu0" + - "--faucet-module-address" + - "0x701c21bf1c8cd5af8c42983890d8ca55e7a820171b8e744c13f2d9998bf76cc3" + - "--faucet-object-id" + - "0xd5723eda84f691ae2623da79312c7909b1737c5b3866ecc5dbd6aa21718ff15d" + - "--discord-token" + - "$(DISCORD_TOKEN)" + env: + - name: DISCORD_TOKEN + valueFrom: + secretKeyRef: + name: rooch-mainnet-secrets + key: discord-token + ports: + - containerPort: 6868 + readinessProbe: + httpGet: + path: / + port: 6868 + initialDelaySeconds: 10 + periodSeconds: 5 + livenessProbe: + httpGet: + path: / + port: 6868 + initialDelaySeconds: 15 + periodSeconds: 10 + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: mainnet-faucet-data \ No newline at end of file diff --git a/kube/rooch-faucet/rooch-faucet-pvc.yaml b/kube/mainnet/faucet/mainnet-faucet-pvc.yaml similarity index 73% rename from kube/rooch-faucet/rooch-faucet-pvc.yaml rename to kube/mainnet/faucet/mainnet-faucet-pvc.yaml index 84e5b923d0..0a55ad4e2f 100644 --- a/kube/rooch-faucet/rooch-faucet-pvc.yaml +++ b/kube/mainnet/faucet/mainnet-faucet-pvc.yaml @@ -1,7 +1,8 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: rooch-faucet-data + name: mainnet-faucet-data + namespace: mainnet spec: accessModes: - ReadWriteOnce diff --git a/kube/mainnet/mainnet-ingress.yaml b/kube/mainnet/mainnet-ingress.yaml new file mode 100644 index 0000000000..7502b38d57 --- /dev/null +++ b/kube/mainnet/mainnet-ingress.yaml @@ -0,0 +1,38 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: mainnet-ingress + namespace: mainnet + annotations: + kubernetes.io/ingress.global-static-ip-name: "mainnet-ingress-static-ip" + #Note: there is a waring: Warning: annotation "kubernetes.io/ingress.class" is deprecated, please use 'spec.ingressClassName' instead + #But if we set the spec.ingressClassName, it do not worked. + kubernetes.io/ingress.class: "gce" + networking.gke.io/managed-certificates: "mainnet-cert" +spec: + rules: + - host: main-faucet.rooch.network + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: mainnet-faucet-service + port: + number: 6868 +--- +apiVersion: v1 +kind: Service +metadata: + name: mainnet-faucet-service + namespace: mainnet +spec: + type: NodePort + ports: + - port: 6868 + targetPort: 6868 + protocol: TCP + name: http + selector: + app: mainnet-faucet \ No newline at end of file diff --git a/kube/mainnet/managed-cert.yaml b/kube/mainnet/managed-cert.yaml new file mode 100644 index 0000000000..cc81821761 --- /dev/null +++ b/kube/mainnet/managed-cert.yaml @@ -0,0 +1,8 @@ +apiVersion: networking.gke.io/v1 +kind: ManagedCertificate +metadata: + name: mainnet-cert + namespace: mainnet +spec: + domains: + - main-faucet.rooch.network \ No newline at end of file diff --git a/kube/mainnet/oracle/mainnet-oracle-binance-deployment.yaml b/kube/mainnet/oracle/mainnet-oracle-binance-deployment.yaml new file mode 100644 index 0000000000..851ccf68f8 --- /dev/null +++ b/kube/mainnet/oracle/mainnet-oracle-binance-deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mainnet-oracle-binance + namespace: mainnet +spec: + replicas: 1 + selector: + matchLabels: + app: mainnet-oracle-binance + template: + metadata: + labels: + app: mainnet-oracle-binance + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias main + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-mainnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-oracle + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "oracle" + - "reporter" + - "--sender" + #the fourth account + - "rooch1mfaa7tnexzyzq3rrcwf5h9u5s3lly7wshcznk69uvn9q4fw5te6qtpwwsg" + - "--oracle-id" + - "0x8316bdaf22b346fcbe43dab84faab08d039cf753a08342164150afcab718c1d2" + - "--oracle-admin-id" + - "0x54dcf30e42ef37ba2fc3f700cecb7f9ab92717247b0e4e8b5e32a54e26ce39cd" + - "--data-source" + - "binance" + - "--ticker" + - "btcusd" + - "--aggregate-strategy" + - "average" + - "--report-interval" + - "10" + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: mainnet-oracle-binance-data \ No newline at end of file diff --git a/kube/mainnet/oracle/mainnet-oracle-binance-pvc.yaml b/kube/mainnet/oracle/mainnet-oracle-binance-pvc.yaml new file mode 100644 index 0000000000..4c9ab5ae63 --- /dev/null +++ b/kube/mainnet/oracle/mainnet-oracle-binance-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mainnet-oracle-binance-data + namespace: mainnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/mainnet/oracle/mainnet-oracle-okx-deployment.yaml b/kube/mainnet/oracle/mainnet-oracle-okx-deployment.yaml new file mode 100644 index 0000000000..53e37703a2 --- /dev/null +++ b/kube/mainnet/oracle/mainnet-oracle-okx-deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mainnet-oracle-okx + namespace: mainnet +spec: + replicas: 1 + selector: + matchLabels: + app: mainnet-oracle-okx + template: + metadata: + labels: + app: mainnet-oracle-okx + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias main + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-mainnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-oracle + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "oracle" + - "reporter" + - "--sender" + #the second account + - "rooch13gcqyg5y7ta9tchlpdmk23ck67d95ah0jf5493g2vhas0ktkwdyqgd0vpq" + - "--oracle-id" + - "0x1b83e993dec577fd5ab73aefa04113bcc15b255c80f87ed9fd9ab0f141757a2b" + - "--oracle-admin-id" + - "0x369f16946b39c0800c6fd2fa61e95afd8ce539d75d70eec21fa1fbdee6932d94" + - "--data-source" + - "okx" + - "--ticker" + - "btcusd" + - "--aggregate-strategy" + - "average" + - "--report-interval" + - "10" + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: mainnet-oracle-okx-data \ No newline at end of file diff --git a/kube/mainnet/oracle/mainnet-oracle-okx-pvc.yaml b/kube/mainnet/oracle/mainnet-oracle-okx-pvc.yaml new file mode 100644 index 0000000000..f0e319dbfd --- /dev/null +++ b/kube/mainnet/oracle/mainnet-oracle-okx-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mainnet-oracle-okx-data + namespace: mainnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/mainnet/oracle/mainnet-oracle-pyth-deployment.yaml b/kube/mainnet/oracle/mainnet-oracle-pyth-deployment.yaml new file mode 100644 index 0000000000..3dfcc3615f --- /dev/null +++ b/kube/mainnet/oracle/mainnet-oracle-pyth-deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mainnet-oracle-pyth + namespace: mainnet +spec: + replicas: 1 + selector: + matchLabels: + app: mainnet-oracle-pyth + template: + metadata: + labels: + app: mainnet-oracle-pyth + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias main + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-mainnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-oracle + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "oracle" + - "reporter" + - "--sender" + #the third account + - "rooch1ydvn7z4tlhhm09a8rt29ma0y5apv0aemx02hpndcrhml5aewv2rqvgll6q" + - "--oracle-id" + - "0x4dabcae5783f5c2da59e5ad828a05ba6f0ec02cf91f4f8266be126dc92d6e5c1" + - "--oracle-admin-id" + - "0x719bfa2c592bd3f90188ac5c95f70b3b743970f10fe91da45f3f4a0f781ae34e" + - "--data-source" + - "pyth" + - "--ticker" + - "btcusd" + - "--aggregate-strategy" + - "average" + - "--report-interval" + - "10" + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: mainnet-oracle-pyth-data \ No newline at end of file diff --git a/kube/mainnet/oracle/mainnet-oracle-pyth-pvc.yaml b/kube/mainnet/oracle/mainnet-oracle-pyth-pvc.yaml new file mode 100644 index 0000000000..9e7b52e8c9 --- /dev/null +++ b/kube/mainnet/oracle/mainnet-oracle-pyth-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mainnet-oracle-pyth-data + namespace: mainnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/mainnet/schedule/mainnet-gas-market-schedule-pvc.yaml b/kube/mainnet/schedule/mainnet-gas-market-schedule-pvc.yaml new file mode 100644 index 0000000000..681c319620 --- /dev/null +++ b/kube/mainnet/schedule/mainnet-gas-market-schedule-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mainnet-gas-market-schedule-data + namespace: mainnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/mainnet/schedule/mainnet-gas-market-schedule.yaml b/kube/mainnet/schedule/mainnet-gas-market-schedule.yaml new file mode 100644 index 0000000000..e1b99e94dd --- /dev/null +++ b/kube/mainnet/schedule/mainnet-gas-market-schedule.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mainnet-gas-market-schedule + namespace: mainnet +spec: + replicas: 1 + selector: + matchLabels: + app: mainnet-gas-market-schedule + template: + metadata: + labels: + app: mainnet-gas-market-schedule + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias main + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-mainnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-schedule + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "task" + - "schedule" + - "--sender" + # the five account + - "rooch1h3sv3a79v7ae76tfhchjh87cqtlpvd9v6s8jmzyazqar6eqcua3qs45djk" + - "--checker-function" + - "0x701c21bf1c8cd5af8c42983890d8ca55e7a820171b8e744c13f2d9998bf76cc3::gas_market::exists_new_events" + - "--checker-args" + - "object:0xdd83de197cc2f4829fc5004ce2a0cb1905601eac24a3f11a1e9c99a926c3dab2" + - "--runner-function" + - "0x701c21bf1c8cd5af8c42983890d8ca55e7a820171b8e744c13f2d9998bf76cc3::gas_market::consume_event" + - "--runner-args" + - "object:0xdd83de197cc2f4829fc5004ce2a0cb1905601eac24a3f11a1e9c99a926c3dab2" + - "--checker-interval" + - "5" + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: mainnet-gas-market-schedule-data \ No newline at end of file diff --git a/kube/rooch-faucet/rooch-faucet-deployment.yaml b/kube/rooch-faucet/rooch-faucet-deployment.yaml deleted file mode 100644 index 6ed1e125ce..0000000000 --- a/kube/rooch-faucet/rooch-faucet-deployment.yaml +++ /dev/null @@ -1,57 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: rooch-faucet -spec: - replicas: 1 - selector: - matchLabels: - app: rooch-faucet - template: - metadata: - labels: - app: rooch-faucet - spec: - initContainers: - - name: init-rooch - image: ghcr.io/rooch-network/rooch:v0.7.0 - command: ["/bin/sh", "-c"] - args: - - | - if [ ! -f /root/.rooch/initialized ]; then - /rooch/rooch init -m "${INIT_SECRET}" --skip-password - /rooch/rooch env switch --alias test - ls -la /root/.rooch/rooch_config/ - touch /root/.rooch/initialized - fi - env: - - name: INIT_SECRET - valueFrom: - secretKeyRef: - name: rooch-faucet-secrets - key: init-phrase - volumeMounts: - - name: rooch-data - mountPath: /root - containers: - - name: rooch-faucet - image: ghcr.io/rooch-network/rooch:v0.7.0 - command: ["/rooch-faucet/rooch-faucet"] - args: - - "--discord-token" - - "$(DISCORD_TOKEN)" - - "--faucet-grant-amount" - - "1000000000" - env: - - name: DISCORD_TOKEN - valueFrom: - secretKeyRef: - name: rooch-faucet-secrets - key: discord-token - volumeMounts: - - name: rooch-data - mountPath: /root - volumes: - - name: rooch-data - persistentVolumeClaim: - claimName: rooch-faucet-data \ No newline at end of file diff --git a/kube/testnet/faucet/testnet-faucet-deployment.yaml b/kube/testnet/faucet/testnet-faucet-deployment.yaml new file mode 100644 index 0000000000..fcb893cebf --- /dev/null +++ b/kube/testnet/faucet/testnet-faucet-deployment.yaml @@ -0,0 +1,82 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: testnet-faucet + namespace: testnet +spec: + replicas: 1 + selector: + matchLabels: + app: testnet-faucet + template: + metadata: + labels: + app: testnet-faucet + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias test + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-testnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-faucet + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "faucet" + - "server" + - "--faucet-sender" + # the first account + - "rooch19p2jn4laz0lum2wcnnf9pdqztw5jymqw9etltj3awwwtydkuykwsas4mgf" + - "--faucet-module-address" + - "0x701c21bf1c8cd5af8c42983890d8ca55e7a820171b8e744c13f2d9998bf76cc3" + - "--faucet-object-id" + - "0xd5723eda84f691ae2623da79312c7909b1737c5b3866ecc5dbd6aa21718ff15d" + - "--discord-token" + - "$(DISCORD_TOKEN)" + env: + - name: DISCORD_TOKEN + valueFrom: + secretKeyRef: + name: rooch-testnet-secrets + key: discord-token + ports: + - containerPort: 6868 + readinessProbe: + httpGet: + path: / + port: 6868 + initialDelaySeconds: 10 + periodSeconds: 5 + livenessProbe: + httpGet: + path: / + port: 6868 + initialDelaySeconds: 15 + periodSeconds: 10 + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: testnet-faucet-data \ No newline at end of file diff --git a/kube/testnet/faucet/testnet-faucet-pvc.yaml b/kube/testnet/faucet/testnet-faucet-pvc.yaml new file mode 100644 index 0000000000..179e66df33 --- /dev/null +++ b/kube/testnet/faucet/testnet-faucet-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: testnet-faucet-data + namespace: testnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/testnet/managed-cert.yaml b/kube/testnet/managed-cert.yaml new file mode 100644 index 0000000000..93d0f160ab --- /dev/null +++ b/kube/testnet/managed-cert.yaml @@ -0,0 +1,8 @@ +apiVersion: networking.gke.io/v1 +kind: ManagedCertificate +metadata: + name: testnet-cert + namespace: testnet +spec: + domains: + - test-faucet.rooch.network \ No newline at end of file diff --git a/kube/testnet/oracle/testnet-oracle-binance-deployment.yaml b/kube/testnet/oracle/testnet-oracle-binance-deployment.yaml new file mode 100644 index 0000000000..18352abe63 --- /dev/null +++ b/kube/testnet/oracle/testnet-oracle-binance-deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: testnet-oracle-binance + namespace: testnet +spec: + replicas: 1 + selector: + matchLabels: + app: testnet-oracle-binance + template: + metadata: + labels: + app: testnet-oracle-binance + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias test + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-testnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-oracle + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "oracle" + - "reporter" + - "--sender" + #the fourth account + - "rooch1h7pdshjeyqcfq8x2jj2ddqhdjzhtjyll0jxw39d87aqp483qp8mqrsul3q" + - "--oracle-id" + - "0x5e56b5fe247d3e77997a1a981cc3103c9a1fa9040ba5054cd831c1fdf1c03a6d" + - "--oracle-admin-id" + - "0xc11d4323a12688492f5abd96cb5e5c1854d8a54562e3dec74c5fd46c7623b684" + - "--data-source" + - "binance" + - "--ticker" + - "btcusd" + - "--aggregate-strategy" + - "average" + - "--report-interval" + - "10" + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: testnet-oracle-binance-data \ No newline at end of file diff --git a/kube/testnet/oracle/testnet-oracle-binance-pvc.yaml b/kube/testnet/oracle/testnet-oracle-binance-pvc.yaml new file mode 100644 index 0000000000..3f701eafd3 --- /dev/null +++ b/kube/testnet/oracle/testnet-oracle-binance-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: testnet-oracle-binance-data + namespace: testnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/testnet/oracle/testnet-oracle-okx-deployment.yaml b/kube/testnet/oracle/testnet-oracle-okx-deployment.yaml new file mode 100644 index 0000000000..3fbe2c154b --- /dev/null +++ b/kube/testnet/oracle/testnet-oracle-okx-deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: testnet-oracle-okx + namespace: testnet +spec: + replicas: 1 + selector: + matchLabels: + app: testnet-oracle-okx + template: + metadata: + labels: + app: testnet-oracle-okx + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias test + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-testnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-oracle + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "oracle" + - "reporter" + - "--sender" + #the second account + - "rooch1nt0yvc6dzhcqpl98htp0ygfpr8vz83zns3hs6hzwgsqndt9q7ewqlrhhz8" + - "--oracle-id" + - "0x107ea9cde1caae6bcb97f2939fff45eff81838bfa1fbdca810f37e51f0d26930" + - "--oracle-admin-id" + - "0x39d4d3a82f8bda01c2c3b00ab03892dd5ba44eb062d828bae5322b07daf326d1" + - "--data-source" + - "okx" + - "--ticker" + - "btcusd" + - "--aggregate-strategy" + - "average" + - "--report-interval" + - "10" + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: testnet-oracle-okx-data \ No newline at end of file diff --git a/kube/testnet/oracle/testnet-oracle-okx-pvc.yaml b/kube/testnet/oracle/testnet-oracle-okx-pvc.yaml new file mode 100644 index 0000000000..8de0083cf0 --- /dev/null +++ b/kube/testnet/oracle/testnet-oracle-okx-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: testnet-oracle-okx-data + namespace: testnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/testnet/oracle/testnet-oracle-pyth-deployment.yaml b/kube/testnet/oracle/testnet-oracle-pyth-deployment.yaml new file mode 100644 index 0000000000..63084c0f53 --- /dev/null +++ b/kube/testnet/oracle/testnet-oracle-pyth-deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: testnet-oracle-pyth + namespace: testnet +spec: + replicas: 1 + selector: + matchLabels: + app: testnet-oracle-pyth + template: + metadata: + labels: + app: testnet-oracle-pyth + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias test + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-testnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-oracle + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "oracle" + - "reporter" + - "--sender" + #the third account + - "rooch1n0fhj4dgwsrekglx0pqqertfh5eehv8cphhxhg2tgjdw48u6er5qe3jwh3" + - "--oracle-id" + - "0x1dced3d6de05a08e229fbba350cfffe159e0e123f54c35cca9f6723b0a5b8b1a" + - "--oracle-admin-id" + - "0xdb5988bfeeca0605aacab4d5b426feafa68af0b26d43be7c5eb3e938b4da65eb" + - "--data-source" + - "pyth" + - "--ticker" + - "btcusd" + - "--aggregate-strategy" + - "average" + - "--report-interval" + - "10" + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: testnet-oracle-pyth-data \ No newline at end of file diff --git a/kube/testnet/oracle/testnet-oracle-pyth-pvc.yaml b/kube/testnet/oracle/testnet-oracle-pyth-pvc.yaml new file mode 100644 index 0000000000..c8df117190 --- /dev/null +++ b/kube/testnet/oracle/testnet-oracle-pyth-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: testnet-oracle-pyth-data + namespace: testnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/testnet/schedule/testnet-gas-market-schedule-pvc.yaml b/kube/testnet/schedule/testnet-gas-market-schedule-pvc.yaml new file mode 100644 index 0000000000..032f3786a5 --- /dev/null +++ b/kube/testnet/schedule/testnet-gas-market-schedule-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: testnet-gas-market-schedule-data + namespace: testnet +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kube/testnet/schedule/testnet-gas-market-schedule.yaml b/kube/testnet/schedule/testnet-gas-market-schedule.yaml new file mode 100644 index 0000000000..da32036965 --- /dev/null +++ b/kube/testnet/schedule/testnet-gas-market-schedule.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: testnet-gas-market-schedule + namespace: testnet +spec: + replicas: 1 + selector: + matchLabels: + app: testnet-gas-market-schedule + template: + metadata: + labels: + app: testnet-gas-market-schedule + spec: + initContainers: + - name: init-rooch + image: ghcr.io/rooch-network/rooch:main + command: ["/bin/sh", "-c"] + args: + - | + if [ ! -f /root/.rooch/initialized ]; then + /rooch/rooch init -m "${INIT_SECRET}" --skip-password + /rooch/rooch env switch --alias test + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + /rooch/rooch account create + ls -la /root/.rooch/rooch_config/ + touch /root/.rooch/initialized + fi + env: + - name: INIT_SECRET + valueFrom: + secretKeyRef: + name: rooch-testnet-secrets + key: init-phrase + volumeMounts: + - name: rooch-data + mountPath: /root + containers: + - name: rooch-schedule + image: ghcr.io/rooch-network/rooch:main + command: ["/rooch/rooch"] + args: + - "task" + - "schedule" + - "--sender" + # the five account + - "rooch1cqqagzda3lsegvz73yp0ga5hppsmpegw06uyusexte4c7fhxg5qqd9x6mw" + - "--checker-function" + - "0x701c21bf1c8cd5af8c42983890d8ca55e7a820171b8e744c13f2d9998bf76cc3::gas_market::exists_new_events" + - "--checker-args" + - "object:0xdd83de197cc2f4829fc5004ce2a0cb1905601eac24a3f11a1e9c99a926c3dab2" + - "--runner-function" + - "0x701c21bf1c8cd5af8c42983890d8ca55e7a820171b8e744c13f2d9998bf76cc3::gas_market::consume_event" + - "--runner-args" + - "object:0xdd83de197cc2f4829fc5004ce2a0cb1905601eac24a3f11a1e9c99a926c3dab2" + - "--checker-interval" + - "5" + volumeMounts: + - name: rooch-data + mountPath: /root + volumes: + - name: rooch-data + persistentVolumeClaim: + claimName: testnet-gas-market-schedule-data \ No newline at end of file diff --git a/kube/testnet/testnet-ingress.yaml b/kube/testnet/testnet-ingress.yaml new file mode 100644 index 0000000000..c822915092 --- /dev/null +++ b/kube/testnet/testnet-ingress.yaml @@ -0,0 +1,38 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: testnet-ingress + namespace: testnet + annotations: + kubernetes.io/ingress.global-static-ip-name: "testnet-ingress-static-ip" + #Note: there is a waring: Warning: annotation "kubernetes.io/ingress.class" is deprecated, please use 'spec.ingressClassName' instead + #But if we set the spec.ingressClassName, it do not worked. + kubernetes.io/ingress.class: "gce" + networking.gke.io/managed-certificates: "testnet-cert" +spec: + rules: + - host: test-faucet.rooch.network + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: testnet-faucet-service + port: + number: 6868 +--- +apiVersion: v1 +kind: Service +metadata: + name: testnet-faucet-service + namespace: testnet +spec: + type: NodePort + ports: + - port: 6868 + targetPort: 6868 + protocol: TCP + name: http + selector: + app: testnet-faucet \ No newline at end of file diff --git a/moveos/raw-store/src/lib.rs b/moveos/raw-store/src/lib.rs index 51e17f0afe..276e9734ff 100644 --- a/moveos/raw-store/src/lib.rs +++ b/moveos/raw-store/src/lib.rs @@ -598,13 +598,13 @@ where } pub fn new_puts(kvs: Vec<(K, V)>) -> Self { - let mut rows = Vec::new(); + let mut rows = Vec::with_capacity(kvs.len()); rows.extend(kvs.into_iter().map(|(k, v)| (k, WriteOp::Value(v)))); Self { rows } } pub fn new_deletes(ks: Vec) -> Self { - let mut rows = Vec::new(); + let mut rows = Vec::with_capacity(ks.len()); rows.extend(ks.into_iter().map(|k| (k, WriteOp::Deletion))); Self { rows } } diff --git a/package.json b/package.json index c2e8a75870..eec2d11e14 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "preinstall": "npx only-allow pnpm", "dashboard": "pnpm --filter ./dashboard", "test-suite": "pnpm --filter ./sdk/typescript/test-suite/", - "rooch-portal": "pnpm --filter ./rooch-portal-v1", "rooch-create": "pnpm --filter ./sdk/typescript/rooch-create/", "rooch-sdk": "pnpm --filter ./sdk/typescript/rooch-sdk/", "rooch-sdk-kit": "pnpm --filter ./sdk/typescript/rooch-sdk-kit/", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a2416ba282..1f6cca43f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -212,11 +212,11 @@ importers: specifier: ^7.7.0 version: 7.16.0(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react@18.3.1))(@mui/material@5.16.7(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.16.7(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@roochnetwork/rooch-sdk': - specifier: ^0.2.4 - version: 0.2.4 + specifier: 0.2.6 + version: 0.2.6(typescript@5.6.2) '@roochnetwork/rooch-sdk-kit': - specifier: ^0.2.4 - version: 0.2.4(@tanstack/react-query@5.56.2(react@18.3.1))(@types/react@18.3.5)(react@18.3.1) + specifier: 0.2.6 + version: 0.2.6(@tanstack/react-query@5.56.2(react@18.3.1))(@types/react@18.3.5)(react@18.3.1)(typescript@5.6.2) '@tanstack/react-query': specifier: ^5.51.11 version: 5.56.2(react@18.3.1) @@ -250,6 +250,9 @@ importers: nprogress: specifier: ^0.2.0 version: 0.2.0 + numeral: + specifier: ^2.0.6 + version: 2.0.6 postcss: specifier: ^8.4.39 version: 8.4.45 @@ -265,6 +268,9 @@ importers: react-syntax-highlighter: specifier: ^15.5.0 version: 15.5.0(react@18.3.1) + react-use: + specifier: ^17.5.1 + version: 17.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) simplebar-react: specifier: ^3.2.5 version: 3.2.6(react@18.3.1) @@ -299,6 +305,9 @@ importers: '@types/nprogress': specifier: ^0.2.3 version: 0.2.3 + '@types/numeral': + specifier: ^2.0.5 + version: 2.0.5 '@types/react': specifier: ^18.3.3 version: 18.3.5 @@ -2683,9 +2692,6 @@ packages: '@emotion/styled': optional: true - '@mysten/bcs@1.0.2': - resolution: {integrity: sha512-haHT0km/9yIIe8lwo8gDFxGLnoxfRF4WmEVCz4lDXbEVQRsZkF0zB97kukiwMjDuFBaGVUhrOMCLz6td8tSMaQ==} - '@mysten/bcs@1.0.4': resolution: {integrity: sha512-6JoQi59GN/dVEBCNq8Rj4uOR0niDrJqDx/2gNQWXANwJakHIGH0AMniHrXP41B2dF+mZ3HVmh9Hi3otiEVQTrQ==} @@ -2900,9 +2906,6 @@ packages: '@noble/curves@1.2.0': resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} - '@noble/curves@1.4.2': - resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} - '@noble/curves@1.6.0': resolution: {integrity: sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==} engines: {node: ^14.21.3 || >=16} @@ -2911,10 +2914,6 @@ packages: resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} engines: {node: '>= 16'} - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} - '@noble/hashes@1.5.0': resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} engines: {node: ^14.21.3 || >=16} @@ -3976,15 +3975,15 @@ packages: cpu: [x64] os: [win32] - '@roochnetwork/rooch-sdk-kit@0.2.4': - resolution: {integrity: sha512-dwrvObq7xuFsM8CjimoOdgNP5biTmwA/k/qy0Zl4KWYCFyh80si5lYhS5oL2muggcMxv6/SYF+xeOCzjUwsNjA==} + '@roochnetwork/rooch-sdk-kit@0.2.6': + resolution: {integrity: sha512-foU39Z4UXHGuRIGP3BJCYaE9tzB5t27avxs1J9a69J8mDYNIiAS9krU8HDmJ8mL7QbzgCuQKLIwKBQjR4180PQ==} engines: {node: '>=18.0.0'} peerDependencies: '@tanstack/react-query': ^5.0.0 react: '*' - '@roochnetwork/rooch-sdk@0.2.4': - resolution: {integrity: sha512-YhPQlAbUJ+zbFXXDyR7r40HruMmy8k/tvO03PJj55LG0EfjJ/UfZ7dC+/I9S6Vt7CGJ8ZExcMne6H6cq1IqECA==} + '@roochnetwork/rooch-sdk@0.2.6': + resolution: {integrity: sha512-4Ox8AjFbNWAflwWnHZe3YxMUee0ZGHnTTegQTppvAvpHlYDxfoxP9tNJbMYeLH/ioV+MTISn9pUgxcBfd/k7wA==} engines: {node: '>=18.0.0'} '@rtsao/scc@1.1.0': @@ -4343,6 +4342,9 @@ packages: '@types/jest@29.5.13': resolution: {integrity: sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==} + '@types/js-cookie@2.2.7': + resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} + '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} @@ -4397,6 +4399,9 @@ packages: '@types/nprogress@0.2.3': resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==} + '@types/numeral@2.0.5': + resolution: {integrity: sha512-kH8I7OSSwQu9DS9JYdFWbuvhVzvFRoCPCkGxNwoGgaPeDfEPJlcxNvEOypZhQ3XXHsGbfIuYcxcJxKUfJHnRfw==} + '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -4801,6 +4806,9 @@ packages: '@vitest/utils@2.1.0': resolution: {integrity: sha512-rreyfVe0PuNqJfKYUwfPDfi6rrp0VSu0Wgvp5WBqJonP+4NvXHk48X6oBam1Lj47Hy6jbJtnMj3OcRdrkTP0tA==} + '@xobotyi/scrollbar-width@1.9.5': + resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -5603,6 +5611,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + core-js-compat@3.38.1: resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==} @@ -5681,9 +5692,16 @@ packages: crypto-browserify@3.12.0: resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} + css-in-js-utils@3.1.0: + resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} + css-select@5.1.0: resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + css-tree@2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -6644,10 +6662,16 @@ packages: fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + fast-shallow-equal@1.0.0: + resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==} + fast-xml-parser@4.5.0: resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} hasBin: true + fastest-stable-stringify@2.0.2: + resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -7101,6 +7125,9 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} + hyphenate-style-name@1.1.0: + resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -7161,6 +7188,9 @@ packages: inline-style-parser@0.1.1: resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} + inline-style-prefixer@7.0.1: + resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==} + internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} @@ -7613,6 +7643,9 @@ packages: joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + js-cookie@2.2.1: + resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + js-sha3@0.9.3: resolution: {integrity: sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==} @@ -7938,6 +7971,9 @@ packages: mdast-util-to-string@3.2.0: resolution: {integrity: sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==} + mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + mdn-data@2.0.28: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} @@ -8253,6 +8289,12 @@ packages: nan@2.20.0: resolution: {integrity: sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==} + nano-css@5.6.2: + resolution: {integrity: sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==} + peerDependencies: + react: '*' + react-dom: '*' + nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -8465,6 +8507,9 @@ packages: nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + numeral@2.0.6: + resolution: {integrity: sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==} + nwsapi@2.2.12: resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==} @@ -9148,6 +9193,18 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' + react-universal-interface@0.6.2: + resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} + peerDependencies: + react: '*' + tslib: '*' + + react-use@17.5.1: + resolution: {integrity: sha512-LG/uPEVRflLWMwi3j/sZqR00nF6JGqTTDblkXK2nzXsIvij06hXl1V/MZIlwj1OKIQUtlh1l9jK8gLsRyCQxMg==} + peerDependencies: + react: '*' + react-dom: '*' + react-zdog@1.2.2: resolution: {integrity: sha512-Ix7ALha91aOEwiHuxumCeYbARS5XNpc/w0v145oGkM6poF/CvhKJwzLhM5sEZbtrghMA+psAhOJkCTzJoseicA==} @@ -9378,6 +9435,9 @@ packages: rrweb-cssom@0.7.1: resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + rtl-css-js@1.16.1: + resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -9424,6 +9484,10 @@ packages: scheduler@0.24.0-canary-efb381bbf-20230505: resolution: {integrity: sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==} + screenfull@5.2.0: + resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==} + engines: {node: '>=0.10.0'} + scroll-into-view-if-needed@3.1.0: resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} @@ -9482,6 +9546,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + set-harmonic-interval@1.0.1: + resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==} + engines: {node: '>=6.9'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -9592,6 +9660,10 @@ packages: source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.5.6: + resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==} + engines: {node: '>=0.10.0'} + source-map@0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} engines: {node: '>=0.10.0'} @@ -9626,6 +9698,9 @@ packages: resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} engines: {node: '>=10.16.0'} + stack-generator@2.0.10: + resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -9636,6 +9711,12 @@ packages: stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + stacktrace-gps@3.1.2: + resolution: {integrity: sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==} + + stacktrace-js@2.0.2: + resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==} + stacktrace-parser@0.1.10: resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} engines: {node: '>=6'} @@ -9909,6 +9990,10 @@ packages: throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + throttle-debounce@3.0.1: + resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} + engines: {node: '>=10'} + through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -9973,6 +10058,9 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -10004,6 +10092,9 @@ packages: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} + ts-easing@0.2.0: + resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -10285,9 +10376,6 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - valibot@0.25.0: - resolution: {integrity: sha512-cmD0ca15oyAbT75iYLNW6uU6doAeIwYfOshpXka/E1Bx4frzbkrgb7gvkI7K0YK/DVOksei4FfxWfRoBP3NFTg==} - valibot@0.41.0: resolution: {integrity: sha512-igDBb8CTYr8YTQlOKgaN9nSS0Be7z+WRuaeYqGf3Cjz3aKmSnqEmYnkfVjzIuumGqfHpa3fLIvMEAfhrpqN8ng==} peerDependencies: @@ -12840,10 +12928,6 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@mysten/bcs@1.0.2': - dependencies: - bs58: 5.0.0 - '@mysten/bcs@1.0.4': dependencies: bs58: 6.0.0 @@ -12977,18 +13061,12 @@ snapshots: dependencies: '@noble/hashes': 1.3.2 - '@noble/curves@1.4.2': - dependencies: - '@noble/hashes': 1.4.0 - '@noble/curves@1.6.0': dependencies: '@noble/hashes': 1.5.0 '@noble/hashes@1.3.2': {} - '@noble/hashes@1.4.0': {} - '@noble/hashes@1.5.0': {} '@noble/secp256k1@1.7.1': {} @@ -14288,9 +14366,9 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.21.3': optional: true - '@roochnetwork/rooch-sdk-kit@0.2.4(@tanstack/react-query@5.56.2(react@18.3.1))(@types/react@18.3.5)(react@18.3.1)': + '@roochnetwork/rooch-sdk-kit@0.2.6(@tanstack/react-query@5.56.2(react@18.3.1))(@types/react@18.3.5)(react@18.3.1)(typescript@5.6.2)': dependencies: - '@roochnetwork/rooch-sdk': 0.2.4 + '@roochnetwork/rooch-sdk': 0.2.6(typescript@5.6.2) '@tanstack/react-query': 5.56.2(react@18.3.1) '@vanilla-extract/css': 1.15.5(babel-plugin-macros@3.1.0) '@vanilla-extract/dynamic': 2.1.2 @@ -14302,21 +14380,24 @@ snapshots: - '@types/react' - babel-plugin-macros - immer + - typescript - '@roochnetwork/rooch-sdk@0.2.4': + '@roochnetwork/rooch-sdk@0.2.6(typescript@5.6.2)': dependencies: - '@mysten/bcs': 1.0.2 - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 + '@mysten/bcs': 1.0.4 + '@noble/curves': 1.6.0 + '@noble/hashes': 1.5.0 '@scure/base': 1.1.8 '@scure/bip32': 1.5.0 '@scure/bip39': 1.4.0 '@suchipi/femver': 1.0.0 bech32: 2.0.0 - bs58check: 2.1.2 + bs58check: 4.0.0 buffer: 6.0.3 tweetnacl: 1.0.3 - valibot: 0.25.0 + valibot: 0.41.0(typescript@5.6.2) + transitivePeerDependencies: + - typescript '@rtsao/scc@1.1.0': {} @@ -14713,6 +14794,8 @@ snapshots: expect: 29.7.0 pretty-format: 29.7.0 + '@types/js-cookie@2.2.7': {} + '@types/js-yaml@4.0.9': {} '@types/json-schema@7.0.15': {} @@ -14761,6 +14844,8 @@ snapshots: '@types/nprogress@0.2.3': {} + '@types/numeral@2.0.5': {} + '@types/parse-json@4.0.2': {} '@types/postcss-prefix-selector@1.16.3': @@ -15416,6 +15501,8 @@ snapshots: loupe: 3.1.1 tinyrainbow: 1.2.0 + '@xobotyi/scrollbar-width@1.9.5': {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -16377,6 +16464,10 @@ snapshots: convert-source-map@2.0.0: {} + copy-to-clipboard@3.3.3: + dependencies: + toggle-selection: 1.0.6 + core-js-compat@3.38.1: dependencies: browserslist: 4.23.3 @@ -16504,6 +16595,10 @@ snapshots: randombytes: 2.1.0 randomfill: 1.0.4 + css-in-js-utils@3.1.0: + dependencies: + hyphenate-style-name: 1.1.0 + css-select@5.1.0: dependencies: boolbase: 1.0.0 @@ -16512,6 +16607,11 @@ snapshots: domutils: 3.1.0 nth-check: 2.1.1 + css-tree@1.1.3: + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + css-tree@2.2.1: dependencies: mdn-data: 2.0.28 @@ -17872,10 +17972,14 @@ snapshots: fast-sha256@1.3.0: {} + fast-shallow-equal@1.0.0: {} + fast-xml-parser@4.5.0: dependencies: strnum: 1.0.5 + fastest-stable-stringify@2.0.2: {} + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -18428,6 +18532,8 @@ snapshots: human-signals@5.0.0: {} + hyphenate-style-name@1.1.0: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -18478,6 +18584,10 @@ snapshots: inline-style-parser@0.1.1: {} + inline-style-prefixer@7.0.1: + dependencies: + css-in-js-utils: 3.1.0 + internal-slot@1.0.7: dependencies: es-errors: 1.3.0 @@ -19085,6 +19195,8 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 + js-cookie@2.2.1: {} + js-sha3@0.9.3: {} js-tokens@4.0.0: {} @@ -19546,6 +19658,8 @@ snapshots: dependencies: '@types/mdast': 3.0.15 + mdn-data@2.0.14: {} + mdn-data@2.0.28: {} mdn-data@2.0.30: {} @@ -20141,6 +20255,19 @@ snapshots: nan@2.20.0: {} + nano-css@5.6.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + css-tree: 1.1.3 + csstype: 3.1.3 + fastest-stable-stringify: 2.0.2 + inline-style-prefixer: 7.0.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + rtl-css-js: 1.16.1 + stacktrace-js: 2.0.2 + stylis: 4.3.4 + nanoid@3.3.7: {} nanoid@5.0.7: {} @@ -20400,6 +20527,8 @@ snapshots: nullthrows@1.1.1: {} + numeral@2.0.6: {} + nwsapi@2.2.12: {} ob1@0.80.12: @@ -21100,6 +21229,30 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + react-universal-interface@0.6.2(react@18.3.1)(tslib@2.7.0): + dependencies: + react: 18.3.1 + tslib: 2.7.0 + + react-use@17.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@types/js-cookie': 2.2.7 + '@xobotyi/scrollbar-width': 1.9.5 + copy-to-clipboard: 3.3.3 + fast-deep-equal: 3.1.3 + fast-shallow-equal: 1.0.0 + js-cookie: 2.2.1 + nano-css: 5.6.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-universal-interface: 0.6.2(react@18.3.1)(tslib@2.7.0) + resize-observer-polyfill: 1.5.1 + screenfull: 5.2.0 + set-harmonic-interval: 1.0.1 + throttle-debounce: 3.0.1 + ts-easing: 0.2.0 + tslib: 2.7.0 + react-zdog@1.2.2: dependencies: react: 18.3.1 @@ -21403,6 +21556,10 @@ snapshots: rrweb-cssom@0.7.1: {} + rtl-css-js@1.16.1: + dependencies: + '@babel/runtime': 7.25.6 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -21458,6 +21615,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + screenfull@5.2.0: {} + scroll-into-view-if-needed@3.1.0: dependencies: compute-scroll-into-view: 3.1.0 @@ -21547,6 +21706,8 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + set-harmonic-interval@1.0.1: {} + setimmediate@1.0.5: {} setprototypeof@1.2.0: {} @@ -21674,6 +21835,8 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map@0.5.6: {} + source-map@0.5.7: {} source-map@0.6.1: {} @@ -21706,6 +21869,10 @@ snapshots: cpu-features: 0.0.10 nan: 2.20.0 + stack-generator@2.0.10: + dependencies: + stackframe: 1.3.4 + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -21714,6 +21881,17 @@ snapshots: stackframe@1.3.4: {} + stacktrace-gps@3.1.2: + dependencies: + source-map: 0.5.6 + stackframe: 1.3.4 + + stacktrace-js@2.0.2: + dependencies: + error-stack-parser: 2.1.4 + stack-generator: 2.0.10 + stacktrace-gps: 3.1.2 + stacktrace-parser@0.1.10: dependencies: type-fest: 0.7.1 @@ -22079,6 +22257,8 @@ snapshots: throat@5.0.0: {} + throttle-debounce@3.0.1: {} + through2@2.0.5: dependencies: readable-stream: 2.3.8 @@ -22130,6 +22310,8 @@ snapshots: dependencies: is-number: 7.0.0 + toggle-selection@1.0.6: {} + toidentifier@1.0.1: {} tough-cookie@4.1.4: @@ -22155,6 +22337,8 @@ snapshots: ts-dedent@2.2.0: {} + ts-easing@0.2.0: {} + ts-interface-checker@0.1.13: {} ts-jest@29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.5.4)(babel-plugin-macros@3.1.0))(typescript@5.6.2): @@ -22455,8 +22639,6 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - valibot@0.25.0: {} - valibot@0.41.0(typescript@5.6.2): optionalDependencies: typescript: 5.6.2 diff --git a/scripts/deploy_rooch_mainnet.sh b/scripts/deploy_rooch_mainnet.sh index 1d8f941b4f..9a6e65c17d 100644 --- a/scripts/deploy_rooch_mainnet.sh +++ b/scripts/deploy_rooch_mainnet.sh @@ -17,5 +17,6 @@ docker run -d --name rooch-mainnet --restart unless-stopped -v /data:/root -p 67 --btc-rpc-url "$BTC_MAIN_RPC_URL" \ --btc-rpc-username rooch-main \ --btc-rpc-password "$BTC_MAIN_RPC_PWD" \ + --da "{\"da-backend\": {\"backends\": [{\"open-da\": {\"scheme\": \"gcs\", \"config\": {\"bucket\": \"$OPENDA_GCP_MAINNET_BUCKET\", \"credential\": \"$OPENDA_GCP_MAINNET_CREDENTIAL\"}}}]}}" \ --traffic-burst-size 100000 \ - --traffic-per-second 10000 + --traffic-per-second 1 diff --git a/scripts/deploy_rooch_testnet.sh b/scripts/deploy_rooch_testnet.sh index d4f2f1ee0f..61c8dac0ee 100644 --- a/scripts/deploy_rooch_testnet.sh +++ b/scripts/deploy_rooch_testnet.sh @@ -20,5 +20,5 @@ docker run -d --name rooch-testnet --restart unless-stopped -v /data:/root -p 67 --btc-rpc-username rooch-test \ --btc-rpc-password "$BTC_TEST_RPC_PWD" \ --traffic-burst-size 100000 \ - --traffic-per-second 10000 \ - --da "{\"internal-da-server\": {\"servers\": [{\"open-da\": {\"scheme\": \"gcs\", \"config\": {\"bucket\": \"$OPENDA_GCP_TESTNET_BUCKET\", \"credential\": \"$OPENDA_GCP_TESTNET_CREDENTIAL\"}}}]}}" + --traffic-per-second 1 \ + --da "{\"da-backend\": {\"backends\": [{\"open-da\": {\"scheme\": \"gcs\", \"config\": {\"bucket\": \"$OPENDA_GCP_TESTNET_BUCKET\", \"credential\": \"$OPENDA_GCP_TESTNET_CREDENTIAL\"}}}]}}" diff --git a/sdk/typescript/rooch-sdk-kit/package.json b/sdk/typescript/rooch-sdk-kit/package.json index e077f0ad3f..42bc8bbbc3 100644 --- a/sdk/typescript/rooch-sdk-kit/package.json +++ b/sdk/typescript/rooch-sdk-kit/package.json @@ -1,7 +1,7 @@ { "name": "@roochnetwork/rooch-sdk-kit", "author": "Rooch.network ", - "version": "0.2.5", + "version": "0.2.7", "description": "Rooch SDK Kit", "license": "Apache-2.0", "engines": { diff --git a/sdk/typescript/rooch-sdk/package.json b/sdk/typescript/rooch-sdk/package.json index 9f687753c6..3bac1b856b 100644 --- a/sdk/typescript/rooch-sdk/package.json +++ b/sdk/typescript/rooch-sdk/package.json @@ -1,7 +1,7 @@ { "name": "@roochnetwork/rooch-sdk", "author": "Rooch.network ", - "version": "0.2.5", + "version": "0.2.7", "description": "Rooch SDK", "license": "Apache-2.0", "engines": { diff --git a/sdk/typescript/rooch-sdk/src/client/networks.ts b/sdk/typescript/rooch-sdk/src/client/networks.ts index 5b7f473cf6..eed8f0797a 100644 --- a/sdk/typescript/rooch-sdk/src/client/networks.ts +++ b/sdk/typescript/rooch-sdk/src/client/networks.ts @@ -1,8 +1,10 @@ // Copyright (c) RoochNetwork // SPDX-License-Identifier: Apache-2.0 -export function getRoochNodeUrl(network: 'testnet' | 'devnet' | 'localnet') { +export function getRoochNodeUrl(network: 'mainnet' | 'testnet' | 'devnet' | 'localnet') { switch (network) { + case 'mainnet': + return 'https://main-seed.rooch.network' case 'testnet': return 'https://test-seed.rooch.network' case 'devnet': diff --git a/sdk/typescript/rooch-sdk/src/client/types/generated.ts b/sdk/typescript/rooch-sdk/src/client/types/generated.ts index bb04a7575d..725716661d 100644 --- a/sdk/typescript/rooch-sdk/src/client/types/generated.ts +++ b/sdk/typescript/rooch-sdk/src/client/types/generated.ts @@ -10,6 +10,12 @@ * /crates/rooch-open-rpc-spec/openrpc.json */ +export interface AccumulatorInfoView { + accumulator_root: string + frozen_subtree_roots: string[] + num_leaves: string + num_nodes: string +} export interface AnnotatedFunctionResultView { return_values?: AnnotatedFunctionReturnValueView[] | null vm_status: VMStatusView @@ -42,13 +48,18 @@ export interface BalanceInfoView { balance: string coin_type: string decimals: number + icon_url?: string | null name: string supply: string symbol: string } -export interface OutPointView { - txid: string - vout: number +export interface BitcoinStatus { + confirmed_block?: BlockHeightHashView | null + pending_block?: BlockHeightHashView | null +} +export interface BlockHeightHashView { + block_hash: string + block_height: string } export interface DisplayFieldsView { fields: { @@ -226,6 +237,7 @@ export interface LedgerTransactionView { } export type LedgerTxDataView = | { + bitcoin_block_hash?: string | null block_hash: string block_height: string chain_id: string @@ -368,6 +380,10 @@ export type OpView = | { modify: string } +export interface OutPointView { + txid: string + vout: number +} /** * `next_cursor` points to the last item in the page; Reading with `next_cursor` will start from the * next item after `next_cursor` if `next_cursor` is `Some`, otherwise it will start from the first @@ -418,6 +434,16 @@ export interface PaginatedInscriptionStateViews { has_next_page: boolean next_cursor?: IndexerStateIDView | null } +/** + * `next_cursor` points to the last item in the page; Reading with `next_cursor` will start from the + * next item after `next_cursor` if `next_cursor` is `Some`, otherwise it will start from the first + * item. + */ +export interface PaginatedStateChangeSetWithTxOrderViews { + data: StateChangeSetWithTxOrderView[] + has_next_page: boolean + next_cursor?: string | null +} /** * `next_cursor` points to the last item in the page; Reading with `next_cursor` will start from the * next item after `next_cursor` if `next_cursor` is `Some`, otherwise it will start from the first @@ -471,6 +497,14 @@ export type RepairIndexerParamsView = | { object_id: string } +export interface RoochStatus { + root_state: RootStateView + sequencer_info: SequencerInfoView +} +export interface RootStateView { + size: string + state_root: string +} export interface SatPointView { offset: string output: OutPointView @@ -480,6 +514,11 @@ export interface ScriptCallView { code: string ty_args: string[] } +export interface SequencerInfoView { + last_accumulator_info: AccumulatorInfoView + last_order: string +} +export type ServiceStatus = 'active' | 'maintenance' | 'read-only-mode' | 'date-import-mode' /** Some specific struct that we want to display in a special way for better readability */ export type SpecificStructView = MoveString | MoveAsciiString | string export interface StateChangeSetView { @@ -487,6 +526,10 @@ export interface StateChangeSetView { global_size: string state_root: string } +export interface StateChangeSetWithTxOrderView { + state_change_set: StateChangeSetView + tx_order: string +} export interface StateKVView { field_key: string state: ObjectStateView @@ -496,7 +539,23 @@ export interface StateOptions { decode?: boolean /** If true, result with display rendered is returned */ showDisplay?: boolean + /** The state root of remote stateDB */ + stateRoot?: string | null +} +export interface Status { + /** The status of the Bitcoin chain */ + bitcoin_status: BitcoinStatus + /** The status of the Rooch chain */ + rooch_status: RoochStatus + /** The status of the rpc service */ + service_status: ServiceStatus } +export type SyncStateFilterView = + /** Sync by object id. */ + | { + object_i_d: string + } + | 'all' export interface TransactionExecutionInfoView { event_root: string gas_used: string diff --git a/sdk/typescript/rooch-sdk/src/client/types/params.ts b/sdk/typescript/rooch-sdk/src/client/types/params.ts index 68c100e466..f1b39e8233 100644 --- a/sdk/typescript/rooch-sdk/src/client/types/params.ts +++ b/sdk/typescript/rooch-sdk/src/client/types/params.ts @@ -148,3 +148,12 @@ export interface RepairIndexerParams { export interface SendRawTransactionParams { txBcsHex: string } +/** Get the chain and service status */ +export interface StatusParams {} +/** Sync state change sets */ +export interface SyncStatesParams { + filter: RpcTypes.SyncStateFilterView + cursor?: string | null | undefined + limit?: string | null | undefined + queryOption?: RpcTypes.QueryOptions | null | undefined +} diff --git a/sdk/typescript/rooch-sdk/src/version.ts b/sdk/typescript/rooch-sdk/src/version.ts index 9d4ef3c3fc..5438bcccd5 100644 --- a/sdk/typescript/rooch-sdk/src/version.ts +++ b/sdk/typescript/rooch-sdk/src/version.ts @@ -3,5 +3,5 @@ // This file is generated by genversion.mjs. Do not edit it directly. -export const PACKAGE_VERSION = '0.2.5' -export const TARGETED_RPC_VERSION = '0.7.2' +export const PACKAGE_VERSION = '0.2.7' +export const TARGETED_RPC_VERSION = '0.7.3' diff --git a/sdk/typescript/rooch-sdk/test-e2e/case/bitcoin.test.ts b/sdk/typescript/rooch-sdk/test-e2e/case/bitcoin.test.ts index d2e7642c12..ff1f5ef3b5 100644 --- a/sdk/typescript/rooch-sdk/test-e2e/case/bitcoin.test.ts +++ b/sdk/typescript/rooch-sdk/test-e2e/case/bitcoin.test.ts @@ -20,9 +20,7 @@ describe('Bitcoin Assets API', () => { }) it('query utxo should be success', async () => { - const addr = testBox.keypair - .getSchnorrPublicKey() - .toAddress().bitcoinAddress.toStr() + const addr = testBox.keypair.getSchnorrPublicKey().toAddress().bitcoinAddress.toStr() const result = await testBox.bitcoinContainer?.executeRpcCommandRaw([], 'generatetoaddress', [ '50', diff --git a/sdk/typescript/templates/react-counter/src/main.tsx b/sdk/typescript/templates/react-counter/src/main.tsx index 3430a50539..731c2cc267 100644 --- a/sdk/typescript/templates/react-counter/src/main.tsx +++ b/sdk/typescript/templates/react-counter/src/main.tsx @@ -15,7 +15,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render( - + diff --git a/sdk/typescript/templates/react-counter/src/networks.ts b/sdk/typescript/templates/react-counter/src/networks.ts index b6b7161b4a..f502b7fb89 100644 --- a/sdk/typescript/templates/react-counter/src/networks.ts +++ b/sdk/typescript/templates/react-counter/src/networks.ts @@ -5,6 +5,12 @@ import { DEVNET_COUNTER_PACKAGE_ID, MAINNET_COUNTER_PACKAGE_ID } from './constan const { networkConfig, useNetworkVariable, useNetworkVariables } = createNetworkConfig({ + mainnet: { + url: getRoochNodeUrl("mainnet"), + variables: { + counterPackageId: DEVNET_COUNTER_PACKAGE_ID, + }, + }, devnet: { url: getRoochNodeUrl("devnet"), variables: {