diff --git a/.vscode/launch.json b/.vscode/launch.json index b18533a9218..836997ec274 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,23 +1,19 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "lldb", "request": "launch", - "name": "Debug unit tests in library 'blockstack_lib'", + "name": "executable 'blockstack-core'", "cargo": { "args": [ - "test", - "--no-run", - "--lib", + "build", + "--bin=blockstack-core", "--package=blockstack-core" ], "filter": { - "name": "blockstack_lib", - "kind": "lib" + "name": "blockstack-core", + "kind": "bin" } }, "args": [], @@ -26,39 +22,51 @@ { "type": "lldb", "request": "launch", - "name": "Debug executable 'blockstack-core' testnet", + "name": "executable 'clarity-cli'", "cargo": { "args": [ "build", - "--bin=blockstack-core", + "--bin=clarity-cli", "--package=blockstack-core" ], "filter": { - "name": "blockstack-core", + "name": "clarity-cli", "kind": "bin" } }, - "args": [ - "testnet", - "${workspaceFolder}/Stacks.toml" - ], - "cwd": "${workspaceFolder}", - "env": { - "RUST_BACKTRACE": "full", - } + "args": [], + "cwd": "${workspaceFolder}" }, { "type": "lldb", "request": "launch", - "name": "Debug executable 'blockstack-core'", + "name": "executable 'blockstack-cli'", "cargo": { "args": [ "build", - "--bin=blockstack-core", + "--bin=blockstack-cli", "--package=blockstack-core" ], "filter": { - "name": "blockstack-core", + "name": "blockstack-cli", + "kind": "bin" + } + }, + "args": ["generate-sk"], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "executable 'bitcoin-neon-controller'", + "cargo": { + "args": [ + "build", + "--bin=bitcoin-neon-controller", + "--package=bitcoin-neon-controller" + ], + "filter": { + "name": "bitcoin-neon-controller", "kind": "bin" } }, @@ -68,17 +76,35 @@ { "type": "lldb", "request": "launch", - "name": "Debug unit tests in executable 'blockstack-core'", + "name": "executable 'stacks-node' -- mocknet", + "cargo": { + "args": [ + "build", + "--bin=stacks-node", + "--package=stacks-node" + ], + "filter": { + "name": "stacks-node", + "kind": "bin" + } + }, + "args": ["mocknet"], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "unit tests in library 'blockstack_lib'", "cargo": { "args": [ "test", "--no-run", - "--bin=blockstack-core", + "--lib", "--package=blockstack-core" ], "filter": { - "name": "blockstack-core", - "kind": "bin" + "name": "blockstack_lib", + "kind": "lib" } }, "args": [], @@ -87,15 +113,16 @@ { "type": "lldb", "request": "launch", - "name": "Debug executable 'clarity-cli'", + "name": "unit tests in executable 'blockstack-core'", "cargo": { "args": [ - "build", - "--bin=clarity-cli", + "test", + "--no-run", + "--bin=blockstack-core", "--package=blockstack-core" ], "filter": { - "name": "clarity-cli", + "name": "blockstack-core", "kind": "bin" } }, @@ -105,7 +132,7 @@ { "type": "lldb", "request": "launch", - "name": "Debug unit tests in executable 'clarity-cli'", + "name": "unit tests in executable 'clarity-cli'", "cargo": { "args": [ "test", @@ -124,10 +151,11 @@ { "type": "lldb", "request": "launch", - "name": "Debug executable 'blockstack-cli'", + "name": "unit tests in executable 'blockstack-cli'", "cargo": { "args": [ - "build", + "test", + "--no-run", "--bin=blockstack-cli", "--package=blockstack-core" ], @@ -142,21 +170,97 @@ { "type": "lldb", "request": "launch", - "name": "Debug unit tests in executable 'blockstack-cli'", + "name": "unit tests in executable 'stacks-node'", "cargo": { "args": [ "test", "--no-run", - "--bin=blockstack-cli", - "--package=blockstack-core" + "--bin=stacks-node", + "--package=stacks-node" ], "filter": { - "name": "blockstack-cli", + "name": "stacks-node", "kind": "bin" } }, "args": [], "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "unit tests in executable 'bitcoin-neon-controller'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=bitcoin-neon-controller", + "--package=bitcoin-neon-controller" + ], + "filter": { + "name": "bitcoin-neon-controller", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "benchmark 'marf_bench'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bench=marf_bench", + "--package=blockstack-core" + ], + "filter": { + "name": "marf_bench", + "kind": "bench" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "benchmark 'large_contract_bench'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bench=large_contract_bench", + "--package=blockstack-core" + ], + "filter": { + "name": "large_contract_bench", + "kind": "bench" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "benchmark 'block_limits'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bench=block_limits", + "--package=blockstack-core" + ], + "filter": { + "name": "block_limits", + "kind": "bench" + } + }, + "args": [], + "cwd": "${workspaceFolder}" } ] } diff --git a/Cargo.lock b/Cargo.lock index af7f6f02015..00d08c20225 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aho-corasick" version = "0.7.13" @@ -147,7 +153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 0.1.10", "libc", "miniz_oxide", "object", @@ -213,7 +219,16 @@ dependencies = [ "block-padding", "byte-tools", "byteorder", - "generic-array", + "generic-array 0.12.3", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", ] [[package]] @@ -247,7 +262,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "sha2", + "sha2 0.8.2", "sha2-asm", "sha3", "slog", @@ -349,6 +364,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "chrono" version = "0.4.19" @@ -422,6 +443,21 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "criterion" version = "0.3.3" @@ -464,7 +500,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils", ] @@ -486,7 +522,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ "autocfg 1.0.0", - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils", "lazy_static", "maybe-uninit", @@ -500,7 +536,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils", "maybe-uninit", ] @@ -512,7 +548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg 1.0.0", - "cfg-if", + "cfg-if 0.1.10", "lazy_static", ] @@ -545,7 +581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" dependencies = [ "byteorder", - "digest", + "digest 0.8.1", "rand_core 0.5.1", "serde", "subtle", @@ -558,7 +594,16 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array", + "generic-array 0.12.3", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", ] [[package]] @@ -567,7 +612,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "dirs-sys", ] @@ -604,7 +649,7 @@ dependencies = [ "curve25519-dalek", "rand 0.7.2", "serde", - "sha2", + "sha2 0.8.2", ] [[package]] @@ -619,7 +664,7 @@ version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8ac63f94732332f44fe654443c46f6375d1939684c17b0afb6cb56b0456e171" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -793,13 +838,23 @@ dependencies = [ "typenum", ] +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check 0.9.2", +] + [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi", ] @@ -1059,6 +1114,24 @@ version = "0.2.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9f8082297d534141b30c8d39e9b1773713ab50fdbe4ff30f750d063b3bfd701" +[[package]] +name = "libflate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389de7875e06476365974da3e7ff85d55f1972188ccd9f6020dd7c8156e17914" +dependencies = [ + "adler32", + "crc32fast", + "libflate_lz77", + "rle-decode-fast", +] + +[[package]] +name = "libflate_lz77" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3286f09f7d4926fc486334f28d8d2e6ebe4f7f9994494b6dab27ddfad2c9b11b" + [[package]] name = "libsqlite3-sys" version = "0.11.1" @@ -1100,7 +1173,7 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -1191,7 +1264,7 @@ version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "fuchsia-zircon", "fuchsia-zircon-sys", "iovec", @@ -1269,7 +1342,7 @@ version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "winapi 0.3.9", ] @@ -1336,6 +1409,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl" version = "0.10.30" @@ -1343,7 +1422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" dependencies = [ "bitflags", - "cfg-if", + "cfg-if 0.1.10", "foreign-types", "lazy_static", "libc", @@ -1385,7 +1464,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "cloudabi", "libc", "redox_syscall", @@ -1553,7 +1632,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0ced56dee39a6e960c15c74dc48849d614586db2eaada6497477af7c7811cd" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "fnv", "lazy_static", "protobuf", @@ -1873,11 +1952,17 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a" dependencies = [ - "block-buffer", - "digest", - "opaque-debug", + "block-buffer 0.7.3", + "digest 0.8.1", + "opaque-debug 0.2.3", ] +[[package]] +name = "rle-decode-fast" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" + [[package]] name = "rusqlite" version = "0.16.0" @@ -2101,10 +2186,10 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.7.3", + "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", ] [[package]] @@ -2119,10 +2204,23 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.7.3", + "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpuid-bool", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -2140,11 +2238,11 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" dependencies = [ - "block-buffer", + "block-buffer 0.7.3", "byte-tools", - "digest", + "digest 0.8.1", "keccak", - "opaque-debug", + "opaque-debug 0.2.3", ] [[package]] @@ -2202,7 +2300,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "redox_syscall", "winapi 0.3.9", @@ -2239,6 +2337,7 @@ dependencies = [ "serde_derive", "serde_json", "slog", + "stx-genesis", "tokio", "toml", "warp", @@ -2302,6 +2401,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "stx-genesis" +version = "0.1.0" +dependencies = [ + "blockstack-core", + "libflate", + "sha2 0.9.2", +] + [[package]] name = "subtle" version = "2.2.3" @@ -2336,7 +2444,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand 0.7.2", "redox_syscall", @@ -2408,7 +2516,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a51cadc5b1eec673a685ff7c33192ff7b7603d0b75446fb354939ee615acb15" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "standback", "stdweb", @@ -2538,7 +2646,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e2a2de6b0d5cbb13fc21193a2296888eaab62b6044479aafb3c54c01c29fcd" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "log 0.4.11", "tracing-core", ] @@ -2746,7 +2854,7 @@ version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "serde", "serde_json", "wasm-bindgen-macro", @@ -2773,7 +2881,7 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41ad6e4e8b2b7f8c90b6e09a9b590ea15cb0d1dbe28502b5a405cd95d1981671" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "js-sys", "wasm-bindgen", "web-sys", diff --git a/Cargo.toml b/Cargo.toml index 2cfd40ca2d7..3cd5cf3e574 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,5 +107,6 @@ sha2-asm = "0.5.3" [workspace] members = [ ".", + "stx-genesis", "testnet/stacks-node", "testnet/bitcoin-neon-controller"] diff --git a/src/chainstate/stacks/db/accounts.rs b/src/chainstate/stacks/db/accounts.rs index 68f71995501..e5735f5faca 100644 --- a/src/chainstate/stacks/db/accounts.rs +++ b/src/chainstate/stacks/db/accounts.rs @@ -210,11 +210,11 @@ impl StacksChainState { pub fn account_genesis_credit( clarity_tx: &mut ClarityTransactionConnection, principal: &PrincipalData, - amount: u64, + amount: u128, ) { clarity_tx .with_clarity_db(|ref mut db| { - let balance = STXBalance::initial(amount as u128); + let balance = STXBalance::initial(amount); let total_balance = balance.get_total_balance(); let mut snapshot = db.get_stx_balance_snapshot_genesis(principal); diff --git a/src/chainstate/stacks/db/mod.rs b/src/chainstate/stacks/db/mod.rs index 7e967dbacaa..3a81f75dfdc 100644 --- a/src/chainstate/stacks/db/mod.rs +++ b/src/chainstate/stacks/db/mod.rs @@ -28,6 +28,7 @@ use rusqlite::Row; use rusqlite::Transaction; use rusqlite::NO_PARAMS; +use std::collections::{hash_map::Entry, HashMap}; use std::fmt; use std::fs; use std::io; @@ -87,6 +88,7 @@ use vm::database::{ }; use vm::representations::ClarityName; use vm::representations::ContractName; +use vm::types::TupleData; use core::CHAINSTATE_VERSION; @@ -593,12 +595,29 @@ pub const MINER_FEE_WINDOW: u64 = 24; // number of blocks (B) used to smooth ove // fraction (out of 100) of the coinbase a user will receive for reporting a microblock stream fork pub const POISON_MICROBLOCK_COMMISSION_FRACTION: u128 = 5; +#[derive(Debug, Clone, Deserialize)] +pub struct VestingSchedule { + pub address: StacksAddress, + pub amount: u64, + pub block_height: u64, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct AccountBalance { + pub address: StacksAddress, + pub amount: u64, +} + pub struct ChainStateBootData { pub first_burnchain_block_hash: BurnchainHeaderHash, pub first_burnchain_block_height: u32, pub first_burnchain_block_timestamp: u32, pub initial_balances: Vec<(PrincipalData, u64)>, pub post_flight_callback: Option ()>>, + pub get_bulk_initial_vesting_schedules: + Option Box>>>, + pub get_bulk_initial_balances: + Option Box>>>, } impl ChainStateBootData { @@ -613,6 +632,8 @@ impl ChainStateBootData { first_burnchain_block_timestamp: burnchain.first_block_timestamp, initial_balances, post_flight_callback, + get_bulk_initial_vesting_schedules: None, + get_bulk_initial_balances: None, } } } @@ -808,14 +829,152 @@ impl StacksChainState { boot_code_account.nonce += 1; } + let mut allocation_events: Vec = vec![]; + info!( + "Initializing chain with {} config balances", + boot_data.initial_balances.len() + ); for (address, amount) in boot_data.initial_balances.iter() { clarity_tx.connection().as_transaction(|clarity| { - StacksChainState::account_genesis_credit(clarity, address, *amount) + StacksChainState::account_genesis_credit(clarity, address, (*amount).into()) }); initial_liquid_ustx = initial_liquid_ustx .checked_add(*amount as u128) .expect("FATAL: liquid STX overflow"); + let mint_event = StacksTransactionEvent::STXEvent(STXEventType::STXMintEvent( + STXMintEventData { + recipient: address.clone(), + amount: *amount as u128, + }, + )); + allocation_events.push(mint_event); + } + + if let Some(get_balances) = boot_data.get_bulk_initial_balances.take() { + info!("Initializing chain with balances"); + let mut balances_count = 0; + clarity_tx.connection().as_transaction(|clarity| { + let initial_balances = get_balances(); + for balance in initial_balances { + balances_count = balances_count + 1; + StacksChainState::account_genesis_credit( + clarity, + &balance.address.into(), + balance.amount.into(), + ); + initial_liquid_ustx = initial_liquid_ustx + .checked_add(balance.amount as u128) + .expect("FATAL: liquid STX overflow"); + let mint_event = StacksTransactionEvent::STXEvent( + STXEventType::STXMintEvent(STXMintEventData { + recipient: balance.address.into(), + amount: balance.amount.into(), + }), + ); + allocation_events.push(mint_event); + } + }); + info!("Done initializing chain with {} balances", balances_count); } + + let allocations_tx = StacksTransaction::new( + tx_version.clone(), + boot_code_auth.clone(), + TransactionPayload::TokenTransfer( + PrincipalData::Standard(boot_code_address.into()), + 0, + TokenTransferMemo([0u8; 34]), + ), + ); + let allocations_receipt = StacksTransactionReceipt::from_stx_transfer( + allocations_tx, + allocation_events, + Value::okay_true(), + ExecutionCost::zero(), + ); + receipts.push(allocations_receipt); + + let mut total_vesting_amount: u128 = 0; + if let Some(get_schedules) = boot_data.get_bulk_initial_vesting_schedules.take() { + info!("Initializing chain with vesting schedules"); + let mut vesting_schedule_count = 0; + clarity_tx.connection().as_transaction(|clarity| { + let initial_vesting_schedules = get_schedules(); + let mut unlocks_per_blocks: HashMap = HashMap::new(); + let lockup_contract_id = boot_code_id("lockup"); + for schedule in initial_vesting_schedules { + total_vesting_amount = total_vesting_amount + .checked_add(schedule.amount as u128) + .expect("FATAL: vesting STX overflow"); + vesting_schedule_count = vesting_schedule_count + 1; + let value = unlocks_per_blocks.get(&schedule.block_height).unwrap_or(&0); + let index = value + 1; + unlocks_per_blocks.insert(schedule.block_height, index); + + clarity + .with_clarity_db(|db| { + let key = TupleData::from_data(vec![ + ( + "stx-height".into(), + Value::UInt(schedule.block_height.into()), + ), + ("index".into(), Value::UInt(index.into())), + ]) + .unwrap(); + + let value = TupleData::from_data(vec![ + ("owner".into(), Value::Principal(schedule.address.into())), + ("metadata".into(), Value::buff_from_byte(0)), + ("unlock-ustx".into(), Value::UInt(schedule.amount.into())), + ]) + .unwrap(); + db.insert_entry( + &lockup_contract_id, + "internal-locked-stx", + Value::Tuple(key), + Value::Tuple(value), + )?; + + let key = TupleData::from_data(vec![( + "stx-height".into(), + Value::UInt(schedule.block_height.into()), + )]) + .unwrap(); + let value = TupleData::from_data(vec![( + "total-unlocked".into(), + Value::UInt(index.into()), + )]) + .unwrap(); + db.insert_entry( + &lockup_contract_id, + "unlocked-stx-per-block", + Value::Tuple(key), + Value::Tuple(value), + )?; + + Ok(()) + }) + .unwrap(); + } + }); + info!( + "Done initializing chain with {} vesting schedules", + vesting_schedule_count + ); + } + + info!( + "Credit lockup contract with balance {}", + total_vesting_amount + ); + clarity_tx.connection().as_transaction(|clarity| { + StacksChainState::account_genesis_credit( + clarity, + &PrincipalData::from(boot_code_id("lockup")), + total_vesting_amount, + ) + }); + if let Some(callback) = boot_data.post_flight_callback.take() { callback(&mut clarity_tx); } @@ -1585,6 +1744,8 @@ pub mod test { first_burnchain_block_hash: BurnchainHeaderHash::zero(), first_burnchain_block_height: 0, first_burnchain_block_timestamp: 0, + get_bulk_initial_vesting_schedules: None, + get_bulk_initial_balances: None, }; StacksChainState::open_and_exec( diff --git a/src/main.rs b/src/main.rs index e87656e3478..e57aa8276c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -466,6 +466,8 @@ fn main() { first_burnchain_block_hash, first_burnchain_block_height: first_burnchain_block_height as u32, first_burnchain_block_timestamp: 0, + get_bulk_initial_vesting_schedules: None, + get_bulk_initial_balances: None, }; let (mut new_chainstate, _) = StacksChainState::open_and_exec( diff --git a/stx-genesis/Cargo.toml b/stx-genesis/Cargo.toml new file mode 100644 index 00000000000..650dbf9c789 --- /dev/null +++ b/stx-genesis/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "stx-genesis" +version = "0.1.0" +authors = ["Matthew Little "] +edition = "2018" + +[dependencies] +libflate = "1.0.3" +stacks = { package = "blockstack-core", path = "../." } + +[lib] +name = "stx_genesis" +path = "src/lib.rs" + +[build-dependencies] +libflate = "1.0.3" +sha2 = "0.9.2" \ No newline at end of file diff --git a/stx-genesis/build.rs b/stx-genesis/build.rs new file mode 100644 index 00000000000..8f03c8713ae --- /dev/null +++ b/stx-genesis/build.rs @@ -0,0 +1,102 @@ +use std::fmt::Write as FmtWrite; +use std::fs; +use std::path::Path; +use std::{ + env, + fs::File, + io::{BufRead, BufReader, Read, Write}, +}; + +use libflate::deflate; +use sha2::{Digest, Sha256}; + +fn main() { + verify_genesis_integrity(); + write_archives().expect("failed to write archives"); + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=chainstate.txt.sha256"); + println!("cargo:rerun-if-changed=chainstate.txt"); +} + +fn open_chainstate_file() -> File { + File::open("chainstate.txt").unwrap() +} + +pub fn write_archives() -> std::io::Result<()> { + let out_dir = env::var_os("OUT_DIR").unwrap(); + { + let chainstate_file = open_chainstate_file(); + let reader = BufReader::new(chainstate_file); + let balances_file_path = Path::new(&out_dir).join("account_balances.gz"); + let balances_file = File::create(balances_file_path)?; + let mut balances_encoder = deflate::Encoder::new(balances_file); + + for line in reader + .lines() + .map(|line| line.unwrap()) + .skip_while(|line| !line.eq(&"-----BEGIN STX BALANCES-----")) + // skip table header line "address,balance" + .skip(2) + .take_while(|line| !line.eq(&"-----END STX BALANCES-----")) + { + balances_encoder.write_all(&[line.as_bytes(), &[b'\n']].concat())?; + } + + let mut balances_file = balances_encoder.finish().into_result().unwrap(); + balances_file.flush()?; + } + { + let chainstate_file = open_chainstate_file(); + let reader = BufReader::new(chainstate_file); + let vesting_file_path = Path::new(&out_dir).join("account_vesting.gz"); + let vesting_file = File::create(vesting_file_path)?; + let mut vesting_encoder = deflate::Encoder::new(vesting_file); + + for line in reader + .lines() + .map(|line| line.unwrap()) + .skip_while(|line| !line.eq(&"-----BEGIN STX VESTING-----")) + // skip table header line "address,value,blocks" + .skip(2) + .take_while(|line| !line.eq(&"-----END STX VESTING-----")) + { + vesting_encoder.write_all(&[line.as_bytes(), &[b'\n']].concat())?; + } + + let mut vesting_file = vesting_encoder.finish().into_result().unwrap(); + vesting_file.flush()?; + } + Ok(()) +} + +fn sha256_digest(mut reader: R) -> String { + let mut hasher = Sha256::new(); + let mut buffer = [0; 1024]; + loop { + let count = reader.read(&mut buffer).unwrap(); + if count == 0 { + break; + } + hasher.update(&buffer[..count]); + } + encode_hex(&hasher.finalize()) +} + +fn encode_hex(bytes: &[u8]) -> String { + let mut s = String::with_capacity(bytes.len() * 2); + for &b in bytes { + write!(&mut s, "{:02x}", b).unwrap(); + } + s +} + +fn verify_genesis_integrity() { + let genesis_data_sha = sha256_digest(open_chainstate_file()); + let expected_genesis_sha = fs::read_to_string("chainstate.txt.sha256").unwrap(); + if !genesis_data_sha.eq_ignore_ascii_case(&expected_genesis_sha) { + panic!( + "FATAL ERROR: chainstate.txt hash mismatch, expected {}, got {}", + expected_genesis_sha, genesis_data_sha + ); + } +} diff --git a/stx-genesis/chainstate.txt b/stx-genesis/chainstate.txt new file mode 100644 index 00000000000..e393b8145c6 --- /dev/null +++ b/stx-genesis/chainstate.txt @@ -0,0 +1,32 @@ +### DEMO / TEST CHAINSTATE DATA + +-----BEGIN STX BALANCES----- +address,balance +31xUrDNFibogSp72hkpP9NQhns9YhekLLv,347222222225 +322XM9xWxso2AV4d7P3D4JFAJd5UjjxVpa,69444444445 +329V64qvhqxpdP2idN93tY3TbE9qasVVEH,347222222225 +32E6hsvSf5TP2TWSBKkccHcDtF5Uk9Mnki,347222222225 +32FCnf9V7CmuP58BNKW6taybVDjpPh9vLx,347222222225 +SM37EFPD9ZVR3YRJE7673MJ3W0T350JM1HVZVCDC3,180555557 +SM28P04DXXDEY3WY02VQJD4TS7VZS00Z6SX54XH5J,356850000 +SM260QHD6ZM2KKPBKZB8PFE5XWP0MHSKTD1B7BHYR,2708333337 +SM1TP7CNY63KQY7DVRDVPNE1X73ND3PT8JX46971V,166667000000 +SM3TJ7J6DR9KFQXQGK9SY7M7AEJT33C8NV639J99C,42311000000 +-----END STX BALANCES----- +-----BEGIN STX VESTING----- +address,value,blocks +112XwWYtXmVGhwKPZAijeDDxeiQzAhvyDi,4139394444,1 +113E1TwrMfBNBitk4oa4uDP4u7ePZynY3Y,2403337500,2 +113bkUpVynUBcEBQBFnMmkLoBze1Ce9KMD,694079167,5 +113bkUpVynUBcEBQBFnMmkLoBze1Ce9KMD,694079167,6587 +3QzEnU6NYVLrdGBEN1FybHSMAynSY4L9TE,13888888889,2162 +3R2NoAcB1kCnUdmgQQvhEELB9fKDasS144,13888888888,41042 +3R2NoAcB1kCnUdmgQQvhEELB9fKDasS144,13888888888,45362 +SM37EFPD9ZVR3YRJE7673MJ3W0T350JM1HVZVCDC3,13888888,45467 +SM28P04DXXDEY3WY02VQJD4TS7VZS00Z6SX54XH5J,27450000,45467 +SM1ZH700J7CEDSEHM5AJ4C4MKKWNESTS35DD3SZM5,13888888,45467 +SM1ZH700J7CEDSEHM5AJ4C4MKKWNESTS35DD3SZM5,13888888,41147 +SM1ZH700J7CEDSEHM5AJ4C4MKKWNESTS35DD3SZM5,13888888,36827 +SM260QHD6ZM2KKPBKZB8PFE5XWP0MHSKTD1B7BHYR,208333333,45467 +SM260QHD6ZM2KKPBKZB8PFE5XWP0MHSKTD1B7BHYR,208333333,2267 +-----END STX VESTING----- diff --git a/stx-genesis/chainstate.txt.sha256 b/stx-genesis/chainstate.txt.sha256 new file mode 100644 index 00000000000..26c4dccedbf --- /dev/null +++ b/stx-genesis/chainstate.txt.sha256 @@ -0,0 +1 @@ +4f57293c77cec345c3ea89eeced83f03234c9e2b3edc3b37f2a131358fcc1de0 \ No newline at end of file diff --git a/stx-genesis/src/lib.rs b/stx-genesis/src/lib.rs new file mode 100644 index 00000000000..b72821b8c55 --- /dev/null +++ b/stx-genesis/src/lib.rs @@ -0,0 +1,67 @@ +use std::io::prelude::*; +use std::io::{self, BufReader}; + +use libflate::deflate; + +use stacks::{ + burnchains::{bitcoin::address::BitcoinAddress, Address}, + chainstate::stacks::db::{AccountBalance, VestingSchedule}, + chainstate::stacks::StacksAddress, +}; + +pub fn read_balances() -> Box> { + let account_balances_bytes = include_bytes!(concat!(env!("OUT_DIR"), "/account_balances.gz")); + let cursor = io::Cursor::new(account_balances_bytes); + let balances_encoder = deflate::Decoder::new(cursor); + let buff_reader = BufReader::new(balances_encoder); + let balances = buff_reader.lines().map(|line| line.unwrap()).map(|line| { + let mut parts = line.split(","); + let addr = parts.next().unwrap(); + let stx_address = parse_genesis_address(&addr).expect(&format!( + "Failed to parsed genesis balance address {}", + addr + )); + let balance = parts.next().unwrap().parse::().unwrap(); + AccountBalance { + address: stx_address, + amount: balance, + } + }); + return Box::new(balances); +} + +pub fn read_vesting() -> Box> { + let account_balances_bytes = include_bytes!(concat!(env!("OUT_DIR"), "/account_vesting.gz")); + let cursor = io::Cursor::new(account_balances_bytes); + let balances_encoder = deflate::Decoder::new(cursor); + let buff_reader = BufReader::new(balances_encoder); + let balances = buff_reader.lines().map(|line| line.unwrap()).map(|line| { + let mut parts = line.split(","); + let addr = parts.next().unwrap(); + let stx_address = parse_genesis_address(&addr).expect(&format!( + "Failed to parsed genesis vesting address {}", + addr + )); + let amount = parts.next().unwrap().parse::().unwrap(); + let block_height = parts.next().unwrap().parse::().unwrap(); + VestingSchedule { + address: stx_address, + amount: amount, + block_height: block_height, + } + }); + return Box::new(balances); +} + +fn parse_genesis_address(addr: &str) -> Option { + // Typical entries are b58 bitcoin addresses that need converted to c32 + match BitcoinAddress::from_b58(&addr) { + Ok(addr) => return Some(StacksAddress::from_bitcoin_address(&addr)), + _ => {} + }; + // A few addresses (from legacy placeholder accounts) are already c32 + match StacksAddress::from_string(addr) { + Some(addr) => return Some(addr), + None => return None, + }; +} diff --git a/testnet/stacks-node/Cargo.toml b/testnet/stacks-node/Cargo.toml index fb91fa0eeb8..d4a70b58f64 100644 --- a/testnet/stacks-node/Cargo.toml +++ b/testnet/stacks-node/Cargo.toml @@ -12,6 +12,7 @@ serde = "1" serde_derive = "1" serde_json = { version = "1.0", features = ["arbitrary_precision", "raw_value"] } stacks = { package = "blockstack-core", path = "../../." } +stx_genesis = { package = "stx-genesis", path = "../../stx-genesis/."} toml = "0.5.6" async-h1 = "=1.0" async-std = { version = "<1.6", features = ["attributes"] } diff --git a/testnet/stacks-node/src/config.rs b/testnet/stacks-node/src/config.rs index 8cbea277b48..f96bb40e172 100644 --- a/testnet/stacks-node/src/config.rs +++ b/testnet/stacks-node/src/config.rs @@ -24,7 +24,7 @@ const MINIMUM_DUST_FEE: u64 = 5500; pub struct ConfigFile { pub burnchain: Option, pub node: Option, - pub mstx_balance: Option>, + pub ustx_balance: Option>, pub events_observer: Option>, pub connection_options: Option, pub block_limit: Option, @@ -80,7 +80,7 @@ impl ConfigFile { ConfigFile { burnchain: Some(burnchain), node: Some(node), - mstx_balance: Some(balances), + ustx_balance: Some(balances), ..ConfigFile::default() } } @@ -123,7 +123,7 @@ impl ConfigFile { ConfigFile { burnchain: Some(burnchain), node: Some(node), - mstx_balance: Some(balances), + ustx_balance: Some(balances), ..ConfigFile::default() } } @@ -166,7 +166,7 @@ impl ConfigFile { ConfigFile { burnchain: Some(burnchain), node: Some(node), - mstx_balance: Some(balances), + ustx_balance: Some(balances), ..ConfigFile::default() } } @@ -208,7 +208,7 @@ impl ConfigFile { ConfigFile { burnchain: Some(burnchain), node: Some(node), - mstx_balance: Some(balances), + ustx_balance: Some(balances), ..ConfigFile::default() } } @@ -443,7 +443,7 @@ impl Config { panic!("Config is missing the setting `burnchain.local_mining_public_key` (mandatory for helium)") } - let initial_balances: Vec = match config_file.mstx_balance { + let initial_balances: Vec = match config_file.ustx_balance { Some(balances) => balances .iter() .map(|balance| { @@ -1080,7 +1080,7 @@ impl EventKeyType { } } -#[derive(Clone)] +#[derive(Debug, Clone, Deserialize)] pub struct InitialBalance { pub address: PrincipalData, pub amount: u64, @@ -1091,3 +1091,10 @@ pub struct InitialBalanceFile { pub address: String, pub amount: u64, } + +#[derive(Clone, Deserialize, Default)] +pub struct InitialVestingScheduleFile { + pub address: String, + pub amount: u64, + pub block_height: u64, +} diff --git a/testnet/stacks-node/src/event_dispatcher.rs b/testnet/stacks-node/src/event_dispatcher.rs index 090bb20c9ae..8f4ee3eae86 100644 --- a/testnet/stacks-node/src/event_dispatcher.rs +++ b/testnet/stacks-node/src/event_dispatcher.rs @@ -2,9 +2,12 @@ use stacks::chainstate::coordinator::BlockEventDispatcher; use stacks::chainstate::stacks::db::StacksHeaderInfo; use stacks::chainstate::stacks::StacksBlock; use std::collections::hash_map::Entry; -use std::collections::{HashMap, HashSet}; use std::thread::sleep; use std::time::Duration; +use std::{ + collections::{HashMap, HashSet}, + sync::{Arc, Mutex}, +}; use async_h1::client; use async_std::net::TcpStream; @@ -199,7 +202,7 @@ impl EventObserver { filtered_events: Vec<(usize, &(bool, Txid, &StacksTransactionEvent))>, chain_tip: &ChainTip, parent_index_hash: &StacksBlockId, - boot_receipts: Option<&Vec>, + boot_receipts: &Vec, winner_txid: &Txid, mature_rewards: &serde_json::Value, ) { @@ -214,20 +217,12 @@ impl EventObserver { let mut tx_index: u32 = 0; let mut serialized_txs = vec![]; - for receipt in chain_tip.receipts.iter() { + for receipt in chain_tip.receipts.iter().chain(boot_receipts.iter()) { let payload = EventObserver::make_new_block_txs_payload(receipt, tx_index); serialized_txs.push(payload); tx_index += 1; } - if let Some(boot_receipts) = boot_receipts { - for receipt in boot_receipts.iter() { - let payload = EventObserver::make_new_block_txs_payload(receipt, tx_index); - serialized_txs.push(payload); - tx_index += 1; - } - } - // Wrap events let payload = json!({ "block_hash": format!("0x{}", chain_tip.block.block_hash()), @@ -259,7 +254,7 @@ pub struct EventDispatcher { mempool_observers_lookup: HashSet, stx_observers_lookup: HashSet, any_event_observers_lookup: HashSet, - boot_receipts: Vec, + boot_receipts: Arc>>>, } impl BlockEventDispatcher for EventDispatcher { @@ -312,7 +307,7 @@ impl EventDispatcher { any_event_observers_lookup: HashSet::new(), burn_block_observers_lookup: HashSet::new(), mempool_observers_lookup: HashSet::new(), - boot_receipts: vec![], + boot_receipts: Arc::new(Mutex::new(None)), } } @@ -366,12 +361,20 @@ impl EventDispatcher { let mut i: usize = 0; let boot_receipts = if chain_tip.metadata.block_height == 1 { - Some(&self.boot_receipts) + let mut boot_receipts_result = self + .boot_receipts + .lock() + .expect("Unexpected concurrent access to `boot_receipts` in the event dispatcher!"); + if let Some(val) = boot_receipts_result.take() { + val + } else { + vec![] + } } else { - None + vec![] }; - for receipt in chain_tip.receipts.iter() { + for receipt in chain_tip.receipts.iter().chain(boot_receipts.iter()) { let tx_hash = receipt.transaction.txid(); for event in receipt.events.iter() { match event { @@ -463,7 +466,7 @@ impl EventDispatcher { filtered_events, chain_tip, parent_index_hash, - boot_receipts, + &boot_receipts, &winner_txid, &mature_rewards, ); @@ -494,7 +497,7 @@ impl EventDispatcher { } pub fn process_boot_receipts(&mut self, receipts: Vec) { - self.boot_receipts = receipts; + self.boot_receipts = Arc::new(Mutex::new(Some(receipts))); } fn update_dispatch_matrix_if_observer_subscribed( diff --git a/testnet/stacks-node/src/main.rs b/testnet/stacks-node/src/main.rs index 1fcd9b15934..ac6c9ad9994 100644 --- a/testnet/stacks-node/src/main.rs +++ b/testnet/stacks-node/src/main.rs @@ -185,7 +185,7 @@ start\t\tStart a node with a config of your own. Can be used for joining a netwo \t\tExample: \t\t stacks-node start --config=/path/to/config.toml -version\t\tDisplay informations about the current version and our release cycle. +version\t\tDisplay information about the current version and our release cycle. help\t\tDisplay this help. diff --git a/testnet/stacks-node/src/node.rs b/testnet/stacks-node/src/node.rs index 71f05706070..8c8b482d1e4 100644 --- a/testnet/stacks-node/src/node.rs +++ b/testnet/stacks-node/src/node.rs @@ -161,6 +161,8 @@ impl Node { first_burnchain_block_height: 0, first_burnchain_block_timestamp: 0, post_flight_callback: Some(boot_block_exec), + get_bulk_initial_vesting_schedules: Some(Box::new(|| stx_genesis::read_vesting())), + get_bulk_initial_balances: Some(Box::new(|| stx_genesis::read_balances())), }; let chain_state_result = StacksChainState::open_and_exec( diff --git a/testnet/stacks-node/src/run_loop/neon.rs b/testnet/stacks-node/src/run_loop/neon.rs index 38ef1c9752f..351a04cb919 100644 --- a/testnet/stacks-node/src/run_loop/neon.rs +++ b/testnet/stacks-node/src/run_loop/neon.rs @@ -188,11 +188,15 @@ impl RunLoop { .expect("Failed to set burnchain parameters in PoX contract"); }); }); - let mut boot_data = ChainStateBootData::new( - &coordinator_burnchain_config, + let mut boot_data = ChainStateBootData { initial_balances, - Some(boot_block), - ); + post_flight_callback: Some(boot_block), + first_burnchain_block_hash: coordinator_burnchain_config.first_block_hash, + first_burnchain_block_height: coordinator_burnchain_config.first_block_height as u32, + first_burnchain_block_timestamp: coordinator_burnchain_config.first_block_timestamp, + get_bulk_initial_vesting_schedules: Some(Box::new(|| stx_genesis::read_vesting())), + get_bulk_initial_balances: Some(Box::new(|| stx_genesis::read_balances())), + }; let (chain_state_db, receipts) = StacksChainState::open_and_exec( mainnet,