diff --git a/core-contracts/Clarinet.toml b/core-contracts/Clarinet.toml new file mode 100644 index 000000000..c4be4c147 --- /dev/null +++ b/core-contracts/Clarinet.toml @@ -0,0 +1,7 @@ + +[project] +name = "core-contracts" + +[contracts.subnets] +path = "../src/chainstate/stacks/boot/subnets.clar" +depends_on = [] diff --git a/core-contracts/settings/Devnet.toml b/core-contracts/settings/Devnet.toml new file mode 100644 index 000000000..bb941fddc --- /dev/null +++ b/core-contracts/settings/Devnet.toml @@ -0,0 +1,73 @@ +[network] +name = "devnet" + +[accounts.deployer] +mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" +balance = 100_000_000_000_000 +# secret_key: 753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601 +# stx_address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM +# btc_address: mqVnk6NPRdhntvfm4hh9vvjiRkFDUuSYsH + +[accounts.wallet_1] +mnemonic = "sell invite acquire kitten bamboo drastic jelly vivid peace spawn twice guilt pave pen trash pretty park cube fragile unaware remain midnight betray rebuild" +balance = 100_000_000_000_000 +# secret_key: 7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801 +# stx_address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5 +# btc_address: mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC + +[accounts.wallet_2] +mnemonic = "hold excess usual excess ring elephant install account glad dry fragile donkey gaze humble truck breeze nation gasp vacuum limb head keep delay hospital" +balance = 100_000_000_000_000 +# secret_key: 530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101 +# stx_address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG +# btc_address: muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG + +[accounts.wallet_3] +mnemonic = "cycle puppy glare enroll cost improve round trend wrist mushroom scorpion tower claim oppose clever elephant dinosaur eight problem before frozen dune wagon high" +balance = 100_000_000_000_000 +# secret_key: d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901 +# stx_address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC +# btc_address: mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7 + +[accounts.wallet_4] +mnemonic = "board list obtain sugar hour worth raven scout denial thunder horse logic fury scorpion fold genuine phrase wealth news aim below celery when cabin" +balance = 100_000_000_000_000 +# secret_key: f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701 +# stx_address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND +# btc_address: mg1C76bNTutiCDV3t9nWhZs3Dc8LzUufj8 + +[accounts.wallet_5] +mnemonic = "hurry aunt blame peanut heavy update captain human rice crime juice adult scale device promote vast project quiz unit note reform update climb purchase" +balance = 100_000_000_000_000 +# secret_key: 3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801 +# stx_address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB +# btc_address: mweN5WVqadScHdA81aATSdcVr4B6dNokqx + +[accounts.wallet_6] +mnemonic = "area desk dutch sign gold cricket dawn toward giggle vibrant indoor bench warfare wagon number tiny universe sand talk dilemma pottery bone trap buddy" +balance = 100_000_000_000_000 +# secret_key: 7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01 +# stx_address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0 +# btc_address: mzxXgV6e4BZSsz8zVHm3TmqbECt7mbuErt + +[accounts.wallet_7] +mnemonic = "prevent gallery kind limb income control noise together echo rival record wedding sense uncover school version force bleak nuclear include danger skirt enact arrow" +balance = 100_000_000_000_000 +# secret_key: b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401 +# stx_address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ +# btc_address: n37mwmru2oaVosgfuvzBwgV2ysCQRrLko7 + +[accounts.wallet_8] +mnemonic = "female adjust gallery certain visit token during great side clown fitness like hurt clip knife warm bench start reunion globe detail dream depend fortune" +balance = 100_000_000_000_000 +# secret_key: 6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01 +# stx_address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP +# btc_address: n2v875jbJ4RjBnTjgbfikDfnwsDV5iUByw + +[accounts.wallet_9] +mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform" +balance = 100_000_000_000_000 +# secret_key: de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801 +# stx_address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 +# btc_address: mjSrB3wS4xab3kYqFktwBzfTdPg367ZJ2d + diff --git a/core-contracts/tests/subnets/subnets_test.ts b/core-contracts/tests/subnets/subnets_test.ts new file mode 100644 index 000000000..910fc2fff --- /dev/null +++ b/core-contracts/tests/subnets/subnets_test.ts @@ -0,0 +1,73 @@ +import { Clarinet, Tx, Chain, Account, Contract, types } from 'https://deno.land/x/clarinet@v0.16.0/index.ts'; +import { assertEquals } from "https://deno.land/std@0.90.0/testing/asserts.ts"; +import { createHash } from "https://deno.land/std@0.107.0/hash/mod.ts"; + +Clarinet.test({ + name: "Ensure that block can be committed by subnet miner", + async fn(chain: Chain, accounts: Map, contracts: Map) { + + // valid miner + const alice = accounts.get("wallet_1")!; + // invalid miner + const bob = accounts.get("wallet_2")!; + const charlie = accounts.get("wallet_3")!; + + // Successfully commit block at height 0 with alice. + let block = chain.mineBlock([ + Tx.contractCall("subnets", "commit-block", + [ + types.buff(new Uint8Array([0, 1, 1, 1, 1])), + types.uint(0), + ], + alice.address), + ]); + assertEquals(block.height, 2); + block.receipts[0].result + .expectOk() + .expectBuff(new Uint8Array([0, 1, 1, 1, 1])); + + + // Try and fail to commit a different block, but again at height 0. + block = chain.mineBlock([ + Tx.contractCall("subnets", "commit-block", + [ + types.buff(new Uint8Array([0, 2, 2, 2, 2])), + types.uint(0), + ], + alice.address), + ]); + assertEquals(block.height, 3); + block.receipts[0].result + .expectErr() + .expectInt(3); + + + // Try and fail to commit a block at height 1 with an invalid miner. + block = chain.mineBlock([ + Tx.contractCall("subnets", "commit-block", + [ + types.buff(new Uint8Array([0, 2, 2, 2, 2])), + types.uint(1), + ], + bob.address), + ]); + assertEquals(block.height, 4); + block.receipts[0].result + .expectErr() + .expectInt(3); + + // Successfully commit block at height 1 with valid miner. + block = chain.mineBlock([ + Tx.contractCall("subnets", "commit-block", + [ + types.buff(new Uint8Array([0, 2, 2, 2, 2])), + types.uint(1), + ], + alice.address), + ]); + assertEquals(block.height, 5); + block.receipts[0].result + .expectOk() + .expectBuff(new Uint8Array([0, 2, 2, 2, 2])); + }, +}); diff --git a/src/chainstate/stacks/boot/subnets.clar b/src/chainstate/stacks/boot/subnets.clar index f1227f0e9..7d8a23c18 100644 --- a/src/chainstate/stacks/boot/subnets.clar +++ b/src/chainstate/stacks/boot/subnets.clar @@ -6,7 +6,8 @@ ;; Map from Stacks block height to block commit (define-map block-commits uint (buff 32)) -(define-constant miners (list 'SPAXYA5XS51713FDTQ8H94EJ4V579CXMTRNBZKSF 'SP3X6QWWETNBZWGBK6DRGTR1KX50S74D3433WDGJY 'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP)) +(define-constant miners (list 'SPAXYA5XS51713FDTQ8H94EJ4V579CXMTRNBZKSF 'SP3X6QWWETNBZWGBK6DRGTR1KX50S74D3433WDGJY + 'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP 'ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5)) ;; Helper function: maps a principal to an optional principal (define-private (map-to-optional (address principal))