From 3ddcab5a7f750b85c864fdf83d9e2dd0f6d19de2 Mon Sep 17 00:00:00 2001 From: tersec Date: Wed, 5 Mar 2025 00:19:02 +0000 Subject: [PATCH] add signing node Electra block tests (#6981) --- .github/workflows/ci.yml | 12 ++-- AllTests-mainnet.md | 2 + tests/test_signing_node.nim | 140 ++++++++++++++++++++++++++++++++++-- 3 files changed, 143 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d4d66061f..59c650e8b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,17 +37,17 @@ jobs: cpu: arm64 - os: windows cpu: amd64 - branch: [~, upstream/version-2-2] + branch: [~, upstream/version-2-0] exclude: - target: os: macos - branch: upstream/version-2-2 + branch: upstream/version-2-0 - target: os: windows - branch: upstream/version-2-2 + branch: upstream/version-2-0 include: - - branch: upstream/version-2-2 - branch-short: version-2-2 + - branch: upstream/version-2-0 + branch-short: version-2-0 nimflags-extra: --mm:refc - target: os: linux @@ -212,7 +212,7 @@ jobs: # allowed to prevent potential problems with downloads on different # file systems". However, GitHub Actions workflows do not support a # usual assortment of string functions. - name: Unit Test Results ${{ matrix.target.os }}-${{ matrix.target.cpu }}-${{ matrix.branch == 'upstream/version-2-2' && 'version-2-2' || matrix.branch }} + name: Unit Test Results ${{ matrix.target.os }}-${{ matrix.target.cpu }}-${{ matrix.branch == 'upstream/version-2-0' && 'version-2-0' || matrix.branch }} path: build/*.xml devbuild: diff --git a/AllTests-mainnet.md b/AllTests-mainnet.md index 260e4f46e0..06e0aa6f4a 100644 --- a/AllTests-mainnet.md +++ b/AllTests-mainnet.md @@ -741,6 +741,7 @@ AllTests-mainnet ## Nimbus remote signer/signing test (verifying-web3signer) ```diff + Signing BeaconBlock (getBlockSignature(deneb)) OK ++ Signing BeaconBlock (getBlockSignature(electra)) OK + Waiting for signing node (/upcheck) test OK ``` ## Nimbus remote signer/signing test (web3signer) @@ -749,6 +750,7 @@ AllTests-mainnet + Public keys enumeration (/api/v1/eth2/publicKeys) test OK + Public keys reload (/reload) test OK + Signing BeaconBlock (getBlockSignature(deneb)) OK ++ Signing BeaconBlock (getBlockSignature(electra)) OK + Signing SC contribution and proof (getContributionAndProofSignature()) OK + Signing SC message (getSyncCommitteeMessage()) OK + Signing SC selection proof (getSyncCommitteeSelectionProof()) OK diff --git a/tests/test_signing_node.nim b/tests/test_signing_node.nim index aff49f0530..e0030cc678 100644 --- a/tests/test_signing_node.nim +++ b/tests/test_signing_node.nim @@ -9,15 +9,18 @@ {.used.} import - unittest2, chronicles, results, stew/[byteutils, io2], + unittest2, chronicles, results, chronos/asyncproc, chronos/unittest2/asynctests, - ../beacon_chain/spec/[signatures, crypto], + ../beacon_chain/spec/crypto, ../beacon_chain/spec/eth2_apis/rest_remote_signer_calls, - ../beacon_chain/filepath, ../beacon_chain/validators/validator_pool from std/os import getEnv, osErrorMsg +from stew/byteutils import hexToByteArray +from ../beacon_chain/filepath import secureCreatePath, secureWriteFile +from ../beacon_chain/spec/signatures import + get_aggregate_and_proof_signature, get_block_signature const TestDirectoryName = "test-signing-node" @@ -64,6 +67,8 @@ const DenebBlockContents = "{\"signed_block\":{\"message\":{\"slot\":\"5297696\",\"proposer_index\":\"153094\",\"parent_root\":\"0xe6106533af9be918120ead7440a8006c7f123cc3cb7daf1f11d951864abea014\",\"state_root\":\"0xf86196d34500ca25d1f4e7431d4d52f6f85540bcaf97dd0d2ad9ecdb3eebcdf0\",\"body\":{\"randao_reveal\":\"0xa7efee3d5ddceb60810b23e3b5d39734696418f41dfd13a0851c7be7a72acbdceaa61e1db27513801917d72519d1c1040ccfed829faf06abe06d9964949554bf4369134b66de715ea49eb4fecf3e2b7e646f1764a1993e31e53dbc6557929c12\",\"eth1_data\":{\"deposit_root\":\"0x8ec87d7219a3c873fff3bfe206b4f923d1b471ce4ff9d6d6ecc162ef07825e14\",\"deposit_count\":\"259476\",\"block_hash\":\"0x877b6f8332c7397251ff3f0c5cecec105ff7d4cb78251b47f91fd15a86a565ab\"},\"graffiti\":\"\",\"proposer_slashings\":[],\"attester_slashings\":[],\"attestations\":[],\"deposits\":[],\"voluntary_exits\":[],\"sync_aggregate\":{\"sync_committee_bits\":\"0x733dfda7f5ffde5ade73367fcbf7fffeef7fe43777ffdffab9dbad6f7eed5fff9bfec4affdefbfaddf35bf5efbff9ffff9dfd7dbf97fbfcdfaddfeffbf95f75f\",\"sync_committee_signature\":\"0x81fdf76e797f81b0116a1c1ae5200b613c8041115223cd89e8bd5477aab13de6097a9ebf42b130c59527bbb4c96811b809353a17c717549f82d4bd336068ef0b99b1feebd4d2432a69fa77fac12b78f1fcc9d7b59edbeb381adf10b15bc4a520\"},\"execution_payload\":{\"parent_hash\":\"0x14c2242a8cfbce559e84c391f5f16d10d7719751b8558873012dc88ae5a193e8\",\"fee_recipient\":\"$1\",\"state_root\":\"0xdf8d96b2c292736d39e72e25802c2744d34d3d3c616de5b362425cab01f72fa5\",\"receipts_root\":\"0x4938a2bf640846d213b156a1a853548b369cd02917fa63d8766ab665d7930bac\",\"logs_bloom\":\"0x298610600038408c201080013832408850a00bc8f801920121840030a015310010e2a0e0108628110552062811441c84802f43825c4fc82140b036c58025a28800054c80a44025c052090a0f2c209a0400058040019ea0008e589084078048050880930113a2894082e0112408b088382402a851621042212aa40018a408d07e178c68691486411aa9a2809043b000a04c040000065a030028018540b04b1820271d00821b00c29059095022322c10a530060223240416140190056608200063c82248274ba8f0098e402041cd9f451031481a1010b8220824833520490221071898802d206348449116812280014a10a2d1c210100a30010802490f0a221849\",\"prev_randao\":\"0xc061711e135cd40531ec3ee29d17d3824c0e5f80d07f721e792ab83240aa0ab5\",\"block_number\":\"8737497\",\"gas_limit\":\"30000000\",\"gas_used\":\"16367052\",\"timestamp\":\"1680080352\",\"extra_data\":\"0xd883010b05846765746888676f312e32302e32856c696e7578\",\"base_fee_per_gas\":\"231613172261\",\"block_hash\":\"0x5aa9fd22a9238925adb2b038fd6eafc77adabf554051db5bc16ae5168a52eff6\",\"transactions\":[],\"withdrawals\":[],\"blob_gas_used\":\"2316131761\",\"excess_blob_gas\":\"231613172261\"},\"bls_to_execution_changes\":[],\"blob_kzg_commitments\":[]}},\"signature\":\"$2\"},\"kzg_proofs\":[],\"blobs\":[]}" + ElectraBlockContents = "{\"signed_block\":{\"message\":{\"slot\":\"5297696\",\"proposer_index\":\"153094\",\"parent_root\":\"0xe6106533af9be918120ead7440a8006c7f123cc3cb7daf1f11d951864abea014\",\"state_root\":\"0xf86196d34500ca25d1f4e7431d4d52f6f85540bcaf97dd0d2ad9ecdb3eebcdf0\",\"body\":{\"randao_reveal\":\"0xa7efee3d5ddceb60810b23e3b5d39734696418f41dfd13a0851c7be7a72acbdceaa61e1db27513801917d72519d1c1040ccfed829faf06abe06d9964949554bf4369134b66de715ea49eb4fecf3e2b7e646f1764a1993e31e53dbc6557929c12\",\"eth1_data\":{\"deposit_root\":\"0x8ec87d7219a3c873fff3bfe206b4f923d1b471ce4ff9d6d6ecc162ef07825e14\",\"deposit_count\":\"259476\",\"block_hash\":\"0x877b6f8332c7397251ff3f0c5cecec105ff7d4cb78251b47f91fd15a86a565ab\"},\"graffiti\":\"\",\"proposer_slashings\":[],\"attester_slashings\":[],\"attestations\":[],\"deposits\":[],\"voluntary_exits\":[],\"sync_aggregate\":{\"sync_committee_bits\":\"0x733dfda7f5ffde5ade73367fcbf7fffeef7fe43777ffdffab9dbad6f7eed5fff9bfec4affdefbfaddf35bf5efbff9ffff9dfd7dbf97fbfcdfaddfeffbf95f75f\",\"sync_committee_signature\":\"0x81fdf76e797f81b0116a1c1ae5200b613c8041115223cd89e8bd5477aab13de6097a9ebf42b130c59527bbb4c96811b809353a17c717549f82d4bd336068ef0b99b1feebd4d2432a69fa77fac12b78f1fcc9d7b59edbeb381adf10b15bc4a520\"},\"execution_payload\":{\"parent_hash\":\"0x14c2242a8cfbce559e84c391f5f16d10d7719751b8558873012dc88ae5a193e8\",\"fee_recipient\":\"$1\",\"state_root\":\"0xdf8d96b2c292736d39e72e25802c2744d34d3d3c616de5b362425cab01f72fa5\",\"receipts_root\":\"0x4938a2bf640846d213b156a1a853548b369cd02917fa63d8766ab665d7930bac\",\"logs_bloom\":\"0x298610600038408c201080013832408850a00bc8f801920121840030a015310010e2a0e0108628110552062811441c84802f43825c4fc82140b036c58025a28800054c80a44025c052090a0f2c209a0400058040019ea0008e589084078048050880930113a2894082e0112408b088382402a851621042212aa40018a408d07e178c68691486411aa9a2809043b000a04c040000065a030028018540b04b1820271d00821b00c29059095022322c10a530060223240416140190056608200063c82248274ba8f0098e402041cd9f451031481a1010b8220824833520490221071898802d206348449116812280014a10a2d1c210100a30010802490f0a221849\",\"prev_randao\":\"0xc061711e135cd40531ec3ee29d17d3824c0e5f80d07f721e792ab83240aa0ab5\",\"block_number\":\"8737497\",\"gas_limit\":\"30000000\",\"gas_used\":\"16367052\",\"timestamp\":\"1680080352\",\"extra_data\":\"0xd883010b05846765746888676f312e32302e32856c696e7578\",\"base_fee_per_gas\":\"231613172261\",\"block_hash\":\"0x5aa9fd22a9238925adb2b038fd6eafc77adabf554051db5bc16ae5168a52eff6\",\"transactions\":[],\"withdrawals\":[],\"blob_gas_used\":\"2316131761\",\"excess_blob_gas\":\"231613172261\"},\"bls_to_execution_changes\":[],\"blob_kzg_commitments\":[],\"execution_requests\":{\"deposits\":[],\"withdrawals\":[],\"consolidations\":[]}}},\"signature\":\"$2\"},\"kzg_proofs\":[],\"blobs\":[]}" + SigningNodeAddress = "127.0.0.1" defaultSigningNodePort = 35333 @@ -98,8 +103,9 @@ proc getBlock( DenebBlockContents % [feeRecipient, SomeSignature], DenebSignedBlockContents).signed_block.message) of ConsensusFork.Electra: - debugComment "electra test signing node getblock" - raiseAssert "electra unsupported" + ForkedBeaconBlock.init(RestJson.decode( + ElectraBlockContents % [feeRecipient, SomeSignature], + ElectraSignedBlockContents).signed_block.message) of ConsensusFork.Fulu: debugFuluComment "electra test signing node getblock" raiseAssert "fulu unsupported" @@ -868,6 +874,41 @@ block: sres2.get() == rres2.get() sres3.get() == rres3.get() + asyncTest "Signing BeaconBlock (getBlockSignature(electra))": + let + forked = getBlock(ConsensusFork.Electra) + blockRoot = withBlck(forked): hash_tree_root(forkyBlck) + + sres1 = + await validator1.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot, forked) + sres2 = + await validator2.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot, forked) + sres3 = + await validator3.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot, forked) + rres1 = + await validator4.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot, forked) + rres2 = + await validator5.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot, forked) + rres3 = + await validator6.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot, forked) + + check: + sres1.isOk() + sres2.isOk() + sres3.isOk() + rres1.isOk() + rres2.isOk() + rres3.isOk() + sres1.get() == rres1.get() + sres2.get() == rres2.get() + sres3.get() == rres3.get() + asyncTest "Connection timeout test": let request = Web3SignerRequest.init(SigningFork, GenesisValidatorsRoot, @@ -1089,5 +1130,94 @@ block: finally: await client.closeWait() + asyncTest "Signing BeaconBlock (getBlockSignature(electra))": + let + fork = ConsensusFork.Electra + forked1 = getBlock(fork) + blockRoot1 = withBlck(forked1): hash_tree_root(forkyBlck) + forked2 = getBlock(fork, SigningOtherFeeRecipient) + blockRoot2 = withBlck(forked2): hash_tree_root(forkyBlck) + request1 = Web3SignerRequest.init(SigningFork, GenesisValidatorsRoot, + Web3SignerForkedBeaconBlock.init(forked1)) + request2 = Web3SignerRequest.init(SigningFork, GenesisValidatorsRoot, + Web3SignerForkedBeaconBlock.init(forked1), @[]) + remoteUrl = "http://" & SigningNodeAddress & ":" & + $getNodePort(basePort, RemoteSignerType.VerifyingWeb3Signer) + prestoFlags = {RestClientFlag.CommaSeparatedArray} + rclient = RestClientRef.new(remoteUrl, prestoFlags, {}) + publicKey1 = ValidatorPubKey.fromHex(ValidatorPubKey1).get() + publicKey2 = ValidatorPubKey.fromHex(ValidatorPubKey2).get() + publicKey3 = ValidatorPubKey.fromHex(ValidatorPubKey3).get() + + check rclient.isOk() + + let + client = rclient.get() + sres1 = + await validator1.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot1, forked1) + sres2 = + await validator2.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot1, forked1) + sres3 = + await validator3.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot1, forked1) + rres1 = + await validator4.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot1, forked1) + rres2 = + await validator5.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot1, forked1) + rres3 = + await validator6.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot1, forked1) + bres1 = + await validator4.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot2, forked2) + bres2 = + await validator5.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot2, forked2) + bres3 = + await validator6.getBlockSignature(SigningFork, GenesisValidatorsRoot, + Slot(1), blockRoot2, forked2) + + check: + # Local requests + sres1.isOk() + sres2.isOk() + sres3.isOk() + # Remote requests with proper Merkle proof of proper FeeRecipent field + rres1.isOk() + rres2.isOk() + rres3.isOk() + # Signature comparison + sres1.get() == rres1.get() + sres2.get() == rres2.get() + sres3.get() == rres3.get() + # Remote requests with changed FeeRecipient field + bres1.isErr() + bres2.isErr() + bres3.isErr() + + try: + let + # `proofs` array is not present. + response1 = await client.signDataPlain(publicKey1, request1) + response2 = await client.signDataPlain(publicKey2, request1) + response3 = await client.signDataPlain(publicKey3, request1) + # `proofs` array is empty. + response4 = await client.signDataPlain(publicKey1, request2) + response5 = await client.signDataPlain(publicKey2, request2) + response6 = await client.signDataPlain(publicKey3, request2) + check: + response1.status == 400 + response2.status == 400 + response3.status == 400 + response4.status == 400 + response5.status == 400 + response6.status == 400 + finally: + await client.closeWait() + waitFor(shutdownSigningNodeProcess(process)) removeTestDir(RemoteSignerType.VerifyingWeb3Signer)