From 59c29fac41e080b71458104ab554d6e333c6a584 Mon Sep 17 00:00:00 2001 From: EclesioMeloJunior Date: Mon, 2 Oct 2023 07:55:40 -0400 Subject: [PATCH] chore: simulate a all zeroes public key without huge state trie --- lib/babe/errors.go | 13 +- lib/runtime/constants.go | 6 + lib/runtime/test_helpers.go | 4 + lib/runtime/wazero/block8077850.yaml | 1 - lib/runtime/wazero/instance_test.go | 187 +++++++++++++++------------ 5 files changed, 129 insertions(+), 82 deletions(-) delete mode 100644 lib/runtime/wazero/block8077850.yaml diff --git a/lib/babe/errors.go b/lib/babe/errors.go index e30f8d0287..273574c234 100644 --- a/lib/babe/errors.go +++ b/lib/babe/errors.go @@ -110,6 +110,7 @@ var ( errInvalidMandatoryDispatch = errors.New("invalid mandatory dispatch") errLookupFailed = errors.New("lookup failed") errValidatorNotFound = errors.New("validator not found") + errBadSigner = errors.New("invalid signing address") ) func newUnknownError(data scale.VaryingDataTypeValue) error { @@ -271,6 +272,14 @@ func (MandatoryDispatch) Index() uint { return 9 } func (MandatoryDispatch) String() string { return "mandatory dispatch" } +// MandatoryDispatch A transaction with a mandatory dispatch +type BadSigner struct{} + +// Index returns VDT index +func (BadSigner) Index() uint { return 10 } + +func (BadSigner) String() string { return "invalid signing address" } + func determineErrType(vdt scale.VaryingDataType) error { vdtVal, err := vdt.Value() if err != nil { @@ -311,6 +320,8 @@ func determineErrType(vdt scale.VaryingDataType) error { return &TransactionValidityError{errValidatorNotFound} case UnknownCustom: return &TransactionValidityError{newUnknownError(val)} + case BadSigner: + return &TransactionValidityError{errBadSigner} } return errInvalidResult @@ -319,7 +330,7 @@ func determineErrType(vdt scale.VaryingDataType) error { func determineErr(res []byte) error { dispatchError := scale.MustNewVaryingDataType(other, CannotLookup{}, BadOrigin{}, Module{}) invalid := scale.MustNewVaryingDataType(Call{}, Payment{}, Future{}, Stale{}, BadProof{}, AncientBirthBlock{}, - ExhaustsResources{}, invalidCustom, BadMandatory{}, MandatoryDispatch{}) + ExhaustsResources{}, invalidCustom, BadMandatory{}, MandatoryDispatch{}, BadSigner{}) unknown := scale.MustNewVaryingDataType(ValidityCannotLookup{}, NoUnsignedValidator{}, unknownCustom) okRes := scale.NewResult(nil, dispatchError) diff --git a/lib/runtime/constants.go b/lib/runtime/constants.go index 26d0ccd267..1c2ee7aaec 100644 --- a/lib/runtime/constants.go +++ b/lib/runtime/constants.go @@ -22,6 +22,12 @@ const ( WESTEND_RUNTIME_V0929_FP = "westend_runtime-v929.compact.wasm" WESTEND_RUNTIME_V0929_URL = "https://github.com/paritytech/polkadot/releases/download/v0.9." + "29/westend_runtime-v9290.compact.compressed.wasm?raw=true" + + // v0.9.12 westend used for zero-address bug + WESTEND_RUNTIME_v0912 = "westend_runtime-v9111" + WESTEND_RUNTIME_V0912_FP = "westend_runtime-v9111.compact.wasm" + WESTEND_RUNTIME_V0912_URL = "https://github.com/paritytech/polkadot/releases/download/v0.9." + + "11/westend_runtime-v9111.compact.compressed.wasm?raw=true" ) const ( diff --git a/lib/runtime/test_helpers.go b/lib/runtime/test_helpers.go index c6a5e836ac..5734761d81 100644 --- a/lib/runtime/test_helpers.go +++ b/lib/runtime/test_helpers.go @@ -78,6 +78,10 @@ func GetRuntime(ctx context.Context, runtime string) ( case WESTEND_RUNTIME_v0929: runtimeFilename = WESTEND_RUNTIME_V0929_FP url = WESTEND_RUNTIME_V0929_URL + // only used for TestInstance_BadSignatureExtrinsic_On_WestendBlock8077850 + case WESTEND_RUNTIME_v0912: + runtimeFilename = WESTEND_RUNTIME_V0912_FP + url = WESTEND_RUNTIME_V0912_URL default: return "", fmt.Errorf("%w: %s", ErrRuntimeUnknown, runtime) } diff --git a/lib/runtime/wazero/block8077850.yaml b/lib/runtime/wazero/block8077850.yaml deleted file mode 100644 index fde2328c3a..0000000000 --- a/lib/runtime/wazero/block8077850.yaml +++ /dev/null @@ -1 +0,0 @@ -blockData: "0x0a91190a200b9220127cd86736564cdc0a513f0dbeac31dbfaa631cc2f3cda5b5941b5d13f12a002af76e1ebbbc00b1a7381ac8954736db041e5395b4a9a56e6e05d3390fe1017f66a08ed016fbc811641487fe2258728ea40d7e8a4469fdc09b7e3f990283e0bc7d32612bd56c48524f36b2a03ff9ecc82cab1809324181ae80558ae46f9e32f2160d52d7f080642414245b50103020000000d594010000000002e37acc5e82ffcc8a9554331ac544793932b71dafbe57960028fae34a6370c27ef3316f1cedd5dc145ac3d1816b5144c8cdc51a3c6a82e9fc3f164eff4a7490e8e928cc4a0f0abeeaafc389995cb94c087eb7d4e8c7aefb34f6ad2b2505ced0905424142450101c2059b255d0cd2e67d1e083516cf30dfafc7691b69723f87e282b846c8b5d630b471000e8f8da1ee292ead5f2e2e3da59ec5d3e21ebfd438a3f0a5507fa186881a0b280402000bb42027e47c011aa715952a042d0040140500000000f45818ef98197100ca6036f3e5f7b042367b575a7d6d501e397157f216fa5a06a7c1a90b1e0bbe118d1cf827f05b565502516fb7e18c2c0a2f5f45d2cbcaee8b1405010000000021628ba81f574b75061af416be8b0cdf6b4963ca5feba406b4fd072c58bb62f8fa59feb9de08e240ddd2c66a118f9e4842737dce6a8975b9a790fbb1f5178a1405020000006a8a7ae20f7a20631d9a44dbcb5003b137461a17453ca0d62846dc751711a745759cddeb4516ba99fbe95c69ad4046deccd32888f3d41076a79f700b142c7a86140503000000162e4ac18181670fdccfcf0931f05733bc70321d8a43816e1509ef50427a4f3232b0892c73f71c7c9831709ccba5bef762b3b71ad756125e60bf6b957ffbf985140504000000ead63a2499fa0f1ac90eaf284e62d0009836eaf2d4ba47d7e53b63d6b8a49209c603c4fdc71d667a21c3dd52b852d8c631dbcc5966c5d6def4cfaf8c8a8b7185140505000000f628891252e6ef7a6a8b711594306bf78d26caeb0b0e40ca5976ff4d6eb8ba0397bd1d2c4f07d76848cca6d944e3ed61654cf71a424297c9945b147659d7238b1401060000007cf0acd39aa1521d8e7873ec69e1b793b1688517a126ce01a4a9480d5ade162ec2b9dfc75cc65a66a1a598562d61d766b3d9ba9b4f3433e8a6a93571d1b9538c140507000000ca9b6c799cd81d35576fef5c6ee87412b673cf0143892aba98cb3147f5d1fd2c0212d99ccf65d77280a99abc008032f4eee3f943aa3f599d764df9384f242e8a140008000000728419c91727f03d6aa7d858bc2e8c6e9dba910e4442fc4506b7308bca6f2e1c6930cfbe3e92bd3afbb9e9926d3bcabc78d9ff6d3c6b27c90e5175167d8ccb80140509000000107f28bcd1d80671c9076f0e99c4bb1c70f3336d485d0648a460cd9a181402265d15b77e40938e96b2f3ddc0f6ab42bfd6270041eadd4e5573751c69fb0a758b14050a00000092dea2960cd1fb2878ae295cd373d4214baa268f31374755677f6cf56a316c482e1e767e47d897c41896977f6e1bc74351749fe0c435078352385070b313f88f14050b0000004c3237449e8195caca8dcae43f0131a6915b90db90db1ecc1e8a8edd39ec824ac56dec01af2355880e1ce42da8f7fd3fedc0d9d9b971d45399ca9dd3e7bf358a14050c0000007e3cb890534d583a422b4643c58da0b1a0500cee334dc68e10e066ddeb45105a92b22bc942450940dc230d615a5a686587ab64e2ef3b6c3ffdfadb440325198314050d000000b610decf556f0a51b8c8a89e7e147f289e17760a8495fb4966b9ec5bc4fd2c72f04af97d47bafcd5d3966d695b72fc3e527580baf4f890fe32bf171124fb408814050e000000b6a4e017d57e1c0b64aad07f93f6d7583daf859154bbc2238fd448e3b23baf76093693c4ebecc0c8e8b79a56c115812cf746371b02979526718f58221d634f8e14050f0000003e0a84fa77fda6fc64574e73b24a662b52311737e0e6e2654f522c45b5afab5c113e9e9b82b1e0b38682de7dbd71cdf9faf3f854c102205f62234c7898b4d7830825080000af76e1ebbbc00b1a7381ac8954736db041e5395b4a9a56e6e05d3390fe1017f6703a5a4e4a00d634f2ddf07eb1f3f8fa8b52dae29ba30869f8b6aea8b46808613c73aef95484853369ee86005e18936b127ef974c2584e5d3e623a9d2457ff0a681d63945c984725fea8d46f1bd572e3a2e516f53173fd5ad7bfa462abdd08aeed1d2e817eaba5563ef2fbfed8f632619edaa289a29c5ee1df8c50e1f914c3af8244912fb66f2f480e56e4af7236b5d7f9aca58de420a23a85b8a05fa68a6f32be23b5c99790aed6f746cde8ffffa0777c77aaa8bb3d7cb41164b5a79a0e738e8beff72d3745c5673e2a727d9e4e0f4935affe9562131eeaa4b6b5729baf7b271d842461610b3b08c6ca9cf6a102719e6e67c672f449fb8ffb3ce6e0af3236b0000000e902ac690a2a774a04c11928d96dc83144b86c93c921b09ef3f38bc469af68c5235416260e00efa41af8bb29c4f46bfd059495d1f3bbf412ba1b3ce1f7374f748a0eea5465a766d5765190affde52b29f24bf15926e5a5547ad3ca7c5c3fcf5f37f765acdc7308066175726120862c2008000000000561757261010128391ef7c5fc6537e371d09ca0182a5cd8c8fc635968d286e831327edac4274e49c958d83f20b5ef1b176fb45ba36aa2667e10497498f2ebbae4818b6ffda88d0000000019427b000c0100a08be53ed8cb90681145084f2813254162ee49b9ea90e04e6268d71461713cef42272c5051e0fe816d77b83f1cbe7770eeb38814e9f4fe17cb97b6fecba5880286c5df28c8c8a259e7a3acddbf373aa74d1655ff49697d50e73053268ba7393e6a3b9c705a91e2e0c9dd9bdf7a0de2cd7b56884abfe76a3d84e7629a49c55e8f01f08ebe1a4d6e02f48eda803f255c44eaf724a69ccfdb445d223cb8342e367205e0d0b51c9e4f2ebc6f09ab8c3a685ea7496c69092e2fa2ed36f8a40bee4f608c0c0736080000af76e1ebbbc00b1a7381ac8954736db041e5395b4a9a56e6e05d3390fe1017f692985cdaa47661ebb5acbe50889f7b81691f6c060df0769adb494f64da3e570bf0f04923e2c070419b133428f6c32a04ce2f0bb974e40ca87d20e404920a9c4398ad7ecea0b1383c0bd4477bb7825c20f0bd2d3bc26ea87e4ca630fa32dfd79cea04127a152ae814a8b7fed3b4af4efdac27c559175cca57ceb69f70902db3cd1c158af1fc7fc602dea7f096c15b9e0ac6908362f1b4681f5e0272361228ae5e68131ecba9a404f95eef573880b7bb83c0e2872f628b1a22ad3f921092b7e1861ea8dd8ac864399cbdbbc0df8a21951e501845e9b0b1b630d17dee6b9561b486690b318a11e9ec8358323f183ada055457655ba4dd1d19e2501ad96d225b2bd9000000e102b5e70a383e9ce6dd0e386da2885b95feb5a4b338d1d8f5fbd3b2d53831dffd6f7916d69ac02fc14b1b3997d95cef8eb986b7f9ec16f18d680382e6b8d331880f459e952304e47d74c855bca175eff27ae7d0eae7aa3604f68d711da20e556caeee8408066175726120862c200800000000056175726101016cfba7237892731d0c80f50f5242e456c8e3ca986c653b85868cfc9cd45540141bd3d2baa79c01bf19992a68c052386c69631b66f8fcd47c56cee2260646ab8e0000000019427b00080144db789df7a23c303c634873433f990ffc99c707bdc73a2e0a5629e3bc48f60453f469c17f8ce3ef38f57c57d8a4a6906b28b028894f21e6527fb5254829938a02443149e7de63f756f643068e5201c510374dde11636e197c2ab14c5415e8630c830f21b3c66d8b1f90d58adc01410c9a780647b9b82cf02397fd7053025b728a0c0300f6d85c67582d62bb95bd375efa28638cdc25e522f00329aa0f044df56ce4a7606608ed01731cea81940165128e1ffdfc5b4207e2ad84548377899b392dc497b1c166dc1f85e8a290268553aa4112f61805c1a7d97f4f7d4df3621fc1bb0e1ac6f32c8306080642414245b50103050000000c594010000000003a66d55fe31b058d993f5ca2b0e5f4111fe22800799e1b17f54398533a719e527e6778a462b294989b2e4409fc803e2570b7751e1d93163fa0b39b742fcc5c0c564f612bdfd8c47a7798539bd449912a856a56a363273e4b713608fcd0ca5208054241424501012c7230a59d24c253682f80889ef75ca60af3ae246768644762546d438c23841496112f05bebcd207ac7f14373566be94cef17431127bc3f95d237eee05abe98a1a92014102840000000000000000000000000000000000000000000000000000000000000000000144d3edd2770853f31b5e2671caae9244ca72185ee8fe629fbe35799392e96c13608f0b3a249539cbeebdcc0212ea139a5369ef8111557a213930cf41c1da3c83450100001202043b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29010000000000" diff --git a/lib/runtime/wazero/instance_test.go b/lib/runtime/wazero/instance_test.go index 502d01d9af..e2686c863c 100644 --- a/lib/runtime/wazero/instance_test.go +++ b/lib/runtime/wazero/instance_test.go @@ -6,16 +6,13 @@ package wazero_runtime import ( _ "embed" - "archive/zip" "bytes" "encoding/json" - "io" "math/big" "os" "path/filepath" "testing" - "github.com/ChainSafe/gossamer/dot/network" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/internal/log" "github.com/ChainSafe/gossamer/lib/common" @@ -28,15 +25,11 @@ import ( "github.com/ChainSafe/gossamer/lib/utils" "github.com/ChainSafe/gossamer/pkg/scale" "github.com/centrifuge/go-substrate-rpc-client/v4/signature" - "gopkg.in/yaml.v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -//go:embed block8077850.yaml -var block8077850 []byte - func mustHexTo64BArray(t *testing.T, inputHex string) (outputArray [64]byte) { t.Helper() copy(outputArray[:], common.MustHexToBytes(inputHex)) @@ -412,83 +405,133 @@ func TestInstance_BabeConfiguration_WestendRuntime_NoAuthorities(t *testing.T) { require.Equal(t, expected, cfg) } -func extractZippedState(t *testing.T, zippedFile, destPath string) { - r, err := zip.OpenReader(zippedFile) - require.NoError(t, err) - require.Equal(t, len(r.File), 1) +func TestInstance_BadSignature_WestendBlock8077850(t *testing.T) { + tests := map[string]struct { + setupRuntime func(t *testing.T) (*Instance, *types.Header) + expectedError []byte + }{ + "westend_dev_runtime_should_fail_with_bad_signature": { + expectedError: []byte{1, 0, 0xa}, + setupRuntime: func(t *testing.T) (*Instance, *types.Header) { + genesisPath := utils.GetWestendDevRawGenesisPath(t) + gen := genesisFromRawJSON(t, genesisPath) + genTrie, err := runtime.NewTrieFromGenesis(gen) + require.NoError(t, err) - f := r.File[0] - outFile, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) - require.NoError(t, err) + //set state to genesis state + genState := storage.NewTrieState(&genTrie) - rc, err := f.Open() - require.NoError(t, err) + cfg := Config{ + Storage: genState, + LogLvl: log.Critical, + } - _, err = io.CopyN(outFile, rc, rc) - require.NoError(t, err) + rt, err := NewRuntimeFromGenesis(cfg) + require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, outFile.Close()) - require.NoError(t, rc.Close()) - require.NoError(t, r.Close()) - }) -} + // reset state back to parent state before executing + parentState := storage.NewTrieState(&genTrie) + rt.SetContextStorage(parentState) -func TestInstance_ExecuteBlock_WestendRuntime_WestendBlock8077850(t *testing.T) { - stateTrieFile := t.TempDir() + "state_block8077850.txt" - extractZippedState(t, "../test_data/westend/state_block8077850.zip", stateTrieFile) + genesisHeader := &types.Header{ + Number: 0, + StateRoot: genTrie.MustHash(), + } - gossTrie8077850 := newTrieFromScaledPairs(t, stateTrieFile) - expectedRoot := common.MustHexToHash("0x731cea81940165128e1ffdfc5b4207e2ad84548377899b392dc497b1c166dc1f") + header := &types.Header{ + ParentHash: genesisHeader.Hash(), + Number: 1, + Digest: types.NewDigest(), + } - require.Equal(t, expectedRoot, gossTrie8077850.MustHash()) + return rt, header + }, + }, + "westend_0912_runtime_should_fail_with_invalid_payment": { + expectedError: []byte{1, 0, 1}, + setupRuntime: func(t *testing.T) (*Instance, *types.Header) { + genesisPath := utils.GetWestendDevRawGenesisPath(t) + gen := genesisFromRawJSON(t, genesisPath) + genTrie, err := runtime.NewTrieFromGenesis(gen) + require.NoError(t, err) - // set state to genesis state - state8077850 := storage.NewTrieState(gossTrie8077850) - cfg := Config{ - Storage: state8077850, - LogLvl: log.Critical, + rt := NewTestInstance(t, runtime.WESTEND_RUNTIME_v0912) + parentState := storage.NewTrieState(&genTrie) + rt.SetContextStorage(parentState) + + genesisHeader := &types.Header{ + Number: 0, + StateRoot: genTrie.MustHash(), + } + + header := &types.Header{ + ParentHash: genesisHeader.Hash(), + Number: 1, + Digest: types.NewDigest(), + } + + return rt, header + }, + }, } - instance, err := NewInstanceFromTrie(gossTrie8077850, cfg) - require.NoError(t, err) + for tname, tt := range tests { + tt := tt - block8077850Data := struct { - BlockData string `yaml:"blockData"` - }{} + t.Run(tname, func(t *testing.T) { + instance, header := tt.setupRuntime(t) - err = yaml.NewDecoder(bytes.NewReader(block8077850)).Decode(&block8077850Data) - require.NoError(t, err) + err := instance.InitializeBlock(header) + require.NoError(t, err) + + idata := types.NewInherentData() + err = idata.SetInherent(types.Timstap0, uint64(5)) + require.NoError(t, err) - entireBlockData := common.MustHexToBytes(block8077850Data.BlockData) + err = idata.SetInherent(types.Babeslot, uint64(1)) + require.NoError(t, err) - blockResponseData := new(network.BlockResponseMessage) - err = blockResponseData.Decode(entireBlockData) - require.NoError(t, err) + ienc, err := idata.Encode() + require.NoError(t, err) - block := &types.Block{ - Header: *blockResponseData.BlockData[0].Header, - Body: *blockResponseData.BlockData[0].Body, - } + // Call BlockBuilder_inherent_extrinsics which returns the inherents as encoded extrinsics + inherentExts, err := instance.InherentExtrinsics(ienc) + require.NoError(t, err) - exts, err := block.Body.AsEncodedExtrinsics() - require.NoError(t, err) + // decode inherent extrinsics + cp := make([]byte, len(inherentExts)) + copy(cp, inherentExts) + var inExts [][]byte + err = scale.Unmarshal(cp, &inExts) + require.NoError(t, err) - expectedExtrinsics := []string{ - "0x8bea0528dc1e7b07896a36d6d2ecb86c6cccbda21064089b5212a081d8b62631", - "0xc0014ff921c3bf55333621237f3058af2d2a696bddf5f703338a7c3b11c1965f", - "0x41b93a99fee24501ddeb1cc2dcfbec938c99a3d94531c7e16b4f4e102a9df38a", - } + // apply each inherent extrinsic + for _, inherent := range inExts { + in, err := scale.Marshal(inherent) + require.NoError(t, err) - var bodyExtrinsicHashes []string - for _, ext := range exts { - bodyExtrinsicHashes = append(bodyExtrinsicHashes, ext.Hash().String()) - } + ret, err := instance.ApplyExtrinsic(in) + require.NoError(t, err) + require.Equal(t, ret, []byte{0, 0}) + } - require.Equal(t, expectedExtrinsics, bodyExtrinsicHashes) + keyring, err := signature.KeyringPairFromSecret( + "0x00000000000000000000000000000000000000000000000000000"+ + "00000000000000000000000000000000000000000000000000000"+ + "0000000000000000000000", 42) + require.NoError(t, err) - _, err = instance.ExecuteBlock(block) - require.NoError(t, err) + extHex := runtime.NewTestExtrinsic(t, instance, header.ParentHash, header.ParentHash, + 0, keyring, "System.remark", []byte{0xab, 0xcd}) + + res, err := instance.ApplyExtrinsic(common.MustHexToBytes(extHex)) + require.NoError(t, err) + + // should fail with transaction validity error: invalid payment for runtime 0.9.12 + // should fail with transaction validity error: bad signature for runtime version greater than 0.9.12 + require.Equal(t, tt.expectedError, res) + }) + } } @@ -1056,22 +1099,6 @@ func newTrieFromPairs(t *testing.T, filename string) *trie.Trie { return &tr } -func newTrieFromScaledPairs(t *testing.T, filename string) *trie.Trie { - data, err := os.ReadFile(filename) - require.NoError(t, err) - - decoded := make([][2][]byte, 0) - err = scale.Unmarshal(data, &decoded) - require.NoError(t, err) - - trie, err := trie.LoadFromEntries(decoded) - if err != nil { - panic(err) - } - - return trie -} - func TestInstance_TransactionPaymentCallApi_QueryCallInfo(t *testing.T) { ins := NewTestInstance(t, runtime.WESTEND_RUNTIME_v0929) tests := []struct {