From d0dc349fd36bd79f94516c866251783641ed12f1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Wed, 31 Aug 2022 16:14:53 +0200 Subject: [PATCH 01/37] graphql: return correct logs for tx (#25612) * graphql: fix tx logs * minor * Use optimized search for selecting tx logs --- graphql/graphql.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 97b460c205ce..66c25841db98 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "math/big" + "sort" "strconv" "github.com/ethereum/go-ethereum" @@ -478,13 +479,16 @@ func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { if err != nil { return nil, err } - ret := make([]*Log, 0, len(logs)) - for _, log := range logs { + var ret []*Log + // Select tx logs from all block logs + ix := sort.Search(len(logs), func(i int) bool { return uint64(logs[i].TxIndex) == t.index }) + for ix < len(logs) && uint64(logs[ix].TxIndex) == t.index { ret = append(ret, &Log{ r: t.r, transaction: t, - log: log, + log: logs[ix], }) + ix++ } return &ret, nil } From 3b41be695e6e12829abf6e5edec0606ee37f14d9 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 13 Sep 2022 21:49:52 +0200 Subject: [PATCH 02/37] graphql: fixes missing tx logs (#25745) * graphql: fix tx logs * graphql: refactor test service setup * graphql: add test for tx logs --- graphql/graphql.go | 2 +- graphql/graphql_test.go | 227 +++++++++++++++++++++------------------- graphql/service.go | 9 +- 3 files changed, 124 insertions(+), 114 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 66c25841db98..356ff669fb16 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -481,7 +481,7 @@ func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { } var ret []*Log // Select tx logs from all block logs - ix := sort.Search(len(logs), func(i int) bool { return uint64(logs[i].TxIndex) == t.index }) + ix := sort.Search(len(logs), func(i int) bool { return uint64(logs[i].TxIndex) >= t.index }) for ix < len(logs) && uint64(logs[ix].TxIndex) == t.index { ret = append(ret, &Log{ r: t.r, diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index d55f4e063486..491c73152113 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -17,6 +17,8 @@ package graphql import ( + "context" + "encoding/json" "fmt" "io" "math/big" @@ -51,15 +53,21 @@ func TestBuildSchema(t *testing.T) { } defer stack.Close() // Make sure the schema can be parsed and matched up to the object model. - if err := newHandler(stack, nil, nil, []string{}, []string{}); err != nil { + if _, err := newHandler(stack, nil, nil, []string{}, []string{}); err != nil { t.Errorf("Could not construct GraphQL handler: %v", err) } } // Tests that a graphQL request is successfully handled when graphql is enabled on the specified endpoint func TestGraphQLBlockSerialization(t *testing.T) { - stack := createNode(t, true, false) + stack := createNode(t) defer stack.Close() + genesis := &core.Genesis{ + Config: params.AllEthashProtocolChanges, + GasLimit: 11500000, + Difficulty: big.NewInt(1048576), + } + newGQLService(t, stack, genesis, 10, func(i int, gen *core.BlockGen) {}) // start node if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) @@ -161,8 +169,55 @@ func TestGraphQLBlockSerialization(t *testing.T) { } func TestGraphQLBlockSerializationEIP2718(t *testing.T) { - stack := createNode(t, true, true) + // Account for signing txes + var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000000000) + dad = common.HexToAddress("0x0000000000000000000000000000000000000dad") + ) + stack := createNode(t) defer stack.Close() + genesis := &core.Genesis{ + Config: params.AllEthashProtocolChanges, + GasLimit: 11500000, + Difficulty: big.NewInt(1048576), + Alloc: core.GenesisAlloc{ + address: {Balance: funds}, + // The address 0xdad sloads 0x00 and 0x01 + dad: { + Code: []byte{byte(vm.PC), byte(vm.PC), byte(vm.SLOAD), byte(vm.SLOAD)}, + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + BaseFee: big.NewInt(params.InitialBaseFee), + } + signer := types.LatestSigner(genesis.Config) + newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(common.Address{1}) + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: uint64(0), + To: &dad, + Value: big.NewInt(100), + Gas: 50000, + GasPrice: big.NewInt(params.InitialBaseFee), + }) + gen.AddTx(tx) + tx, _ = types.SignNewTx(key, signer, &types.AccessListTx{ + ChainID: genesis.Config.ChainID, + Nonce: uint64(1), + To: &dad, + Gas: 30000, + GasPrice: big.NewInt(params.InitialBaseFee), + Value: big.NewInt(50), + AccessList: types.AccessList{{ + Address: dad, + StorageKeys: []common.Hash{{0}}, + }}, + }) + gen.AddTx(tx) + }) // start node if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) @@ -198,7 +253,7 @@ func TestGraphQLBlockSerializationEIP2718(t *testing.T) { // Tests that a graphQL request is not handled successfully when graphql is not enabled on the specified endpoint func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) { - stack := createNode(t, false, false) + stack := createNode(t) defer stack.Close() if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) @@ -212,7 +267,59 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) } -func createNode(t *testing.T, gqlEnabled bool, txEnabled bool) *node.Node { +func TestGraphQLTransactionLogs(t *testing.T) { + var ( + key, _ = crypto.GenerateKey() + addr = crypto.PubkeyToAddress(key.PublicKey) + dadStr = "0x0000000000000000000000000000000000000dad" + dad = common.HexToAddress(dadStr) + genesis = &core.Genesis{ + Config: params.AllEthashProtocolChanges, + GasLimit: 11500000, + Difficulty: big.NewInt(1048576), + Alloc: core.GenesisAlloc{ + addr: {Balance: big.NewInt(params.Ether)}, + dad: { + // LOG0(0, 0), LOG0(0, 0), RETURN(0, 0) + Code: common.Hex2Bytes("60006000a060006000a060006000f3"), + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + signer = types.LatestSigner(genesis.Config) + stack = createNode(t) + ) + defer stack.Close() + + handler := newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + gen.AddTx(tx) + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Nonce: 1, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + gen.AddTx(tx) + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Nonce: 2, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + gen.AddTx(tx) + }) + // start node + if err := stack.Start(); err != nil { + t.Fatalf("could not start node: %v", err) + } + query := `{block { transactions { logs { account { address } } } } }` + res := handler.Schema.Exec(context.Background(), query, "", map[string]interface{}{}) + if res.Errors != nil { + t.Fatalf("graphql query failed: %v", res.Errors) + } + have, err := json.Marshal(res.Data) + if err != nil { + t.Fatalf("failed to encode graphql response: %s", err) + } + want := fmt.Sprintf(`{"block":{"transactions":[{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]}]}}`, dadStr, dadStr, dadStr, dadStr, dadStr, dadStr) + if string(have) != want { + t.Errorf("response unmatch. expected %s, got %s", want, have) + } +} + +func createNode(t *testing.T) *node.Node { stack, err := node.New(&node.Config{ HTTPHost: "127.0.0.1", HTTPPort: 0, @@ -222,83 +329,12 @@ func createNode(t *testing.T, gqlEnabled bool, txEnabled bool) *node.Node { if err != nil { t.Fatalf("could not create node: %v", err) } - if !gqlEnabled { - return stack - } - if !txEnabled { - createGQLService(t, stack) - } else { - createGQLServiceWithTransactions(t, stack) - } return stack } -func createGQLService(t *testing.T, stack *node.Node) { - // create backend - ethConf := ðconfig.Config{ - Genesis: &core.Genesis{ - Config: params.AllEthashProtocolChanges, - GasLimit: 11500000, - Difficulty: big.NewInt(1048576), - }, - Ethash: ethash.Config{ - PowMode: ethash.ModeFake, - }, - NetworkId: 1337, - TrieCleanCache: 5, - TrieCleanCacheJournal: "triecache", - TrieCleanCacheRejournal: 60 * time.Minute, - TrieDirtyCache: 5, - TrieTimeout: 60 * time.Minute, - SnapshotCache: 5, - } - ethBackend, err := eth.New(stack, ethConf) - if err != nil { - t.Fatalf("could not create eth backend: %v", err) - } - // Create some blocks and import them - chain, _ := core.GenerateChain(params.AllEthashProtocolChanges, ethBackend.BlockChain().Genesis(), - ethash.NewFaker(), ethBackend.ChainDb(), 10, func(i int, gen *core.BlockGen) {}) - _, err = ethBackend.BlockChain().InsertChain(chain) - if err != nil { - t.Fatalf("could not create import blocks: %v", err) - } - // create gql service - filterSystem := filters.NewFilterSystem(ethBackend.APIBackend, filters.Config{}) - err = New(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{}) - if err != nil { - t.Fatalf("could not create graphql service: %v", err) - } -} - -func createGQLServiceWithTransactions(t *testing.T, stack *node.Node) { - // create backend - key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address := crypto.PubkeyToAddress(key.PublicKey) - funds := big.NewInt(1000000000000000) - dad := common.HexToAddress("0x0000000000000000000000000000000000000dad") - +func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) *handler { ethConf := ðconfig.Config{ - Genesis: &core.Genesis{ - Config: params.AllEthashProtocolChanges, - GasLimit: 11500000, - Difficulty: big.NewInt(1048576), - Alloc: core.GenesisAlloc{ - address: {Balance: funds}, - // The address 0xdad sloads 0x00 and 0x01 - dad: { - Code: []byte{ - byte(vm.PC), - byte(vm.PC), - byte(vm.SLOAD), - byte(vm.SLOAD), - }, - Nonce: 0, - Balance: big.NewInt(0), - }, - }, - BaseFee: big.NewInt(params.InitialBaseFee), - }, + Genesis: gspec, Ethash: ethash.Config{ PowMode: ethash.ModeFake, }, @@ -310,49 +346,22 @@ func createGQLServiceWithTransactions(t *testing.T, stack *node.Node) { TrieTimeout: 60 * time.Minute, SnapshotCache: 5, } - ethBackend, err := eth.New(stack, ethConf) if err != nil { t.Fatalf("could not create eth backend: %v", err) } - signer := types.LatestSigner(ethConf.Genesis.Config) - - legacyTx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ - Nonce: uint64(0), - To: &dad, - Value: big.NewInt(100), - Gas: 50000, - GasPrice: big.NewInt(params.InitialBaseFee), - }) - envelopTx, _ := types.SignNewTx(key, signer, &types.AccessListTx{ - ChainID: ethConf.Genesis.Config.ChainID, - Nonce: uint64(1), - To: &dad, - Gas: 30000, - GasPrice: big.NewInt(params.InitialBaseFee), - Value: big.NewInt(50), - AccessList: types.AccessList{{ - Address: dad, - StorageKeys: []common.Hash{{0}}, - }}, - }) - // Create some blocks and import them chain, _ := core.GenerateChain(params.AllEthashProtocolChanges, ethBackend.BlockChain().Genesis(), - ethash.NewFaker(), ethBackend.ChainDb(), 1, func(i int, b *core.BlockGen) { - b.SetCoinbase(common.Address{1}) - b.AddTx(legacyTx) - b.AddTx(envelopTx) - }) - + ethash.NewFaker(), ethBackend.ChainDb(), genBlocks, genfunc) _, err = ethBackend.BlockChain().InsertChain(chain) if err != nil { t.Fatalf("could not create import blocks: %v", err) } - // create gql service + // Set up handler filterSystem := filters.NewFilterSystem(ethBackend.APIBackend, filters.Config{}) - err = New(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{}) + handler, err := newHandler(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{}) if err != nil { t.Fatalf("could not create graphql service: %v", err) } + return handler } diff --git a/graphql/service.go b/graphql/service.go index 019026bc7ea7..6f6e58335991 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -57,17 +57,18 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // New constructs a new GraphQL service instance. func New(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error { - return newHandler(stack, backend, filterSystem, cors, vhosts) + _, err := newHandler(stack, backend, filterSystem, cors, vhosts) + return err } // newHandler returns a new `http.Handler` that will answer GraphQL queries. // It additionally exports an interactive query browser on the / endpoint. -func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error { +func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) (*handler, error) { q := Resolver{backend, filterSystem} s, err := graphql.ParseSchema(schema, &q) if err != nil { - return err + return nil, err } h := handler{Schema: s} handler := node.NewHTTPHandlerStack(h, cors, vhosts, nil) @@ -76,5 +77,5 @@ func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters. stack.RegisterHandler("GraphQL", "/graphql", handler) stack.RegisterHandler("GraphQL", "/graphql/", handler) - return nil + return &h, nil } From 972007a517c49ee9e2a359950d81c74467492ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 14 Sep 2022 11:07:10 +0200 Subject: [PATCH 03/37] Release Geth v1.10.24 --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/version.go b/params/version.go index 5f24b41f2852..349bdf1c18d1 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 10 // Minor version component of the current release - VersionPatch = 23 // Patch version component of the current release + VersionPatch = 24 // Patch version component of the current release VersionMeta = "stable" // Version metadata to append to the version string ) From 8f61fc8b73565ff15d27fd9731b945d9d1878ec3 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 15 Sep 2022 17:50:54 +0200 Subject: [PATCH 04/37] params: set TerminalTotalDifficultyPassed to true (#25769) * params: set TerminalTotalDifficultyPassed to true * Update params/config.go Co-authored-by: Martin Holst Swende --- params/config.go | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/params/config.go b/params/config.go index 4d6eec8939bc..80e671f9bf41 100644 --- a/params/config.go +++ b/params/config.go @@ -59,25 +59,26 @@ var ( // MainnetChainConfig is the chain parameters to run a node on the main network. MainnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(1_150_000), - DAOForkBlock: big.NewInt(1_920_000), - DAOForkSupport: true, - EIP150Block: big.NewInt(2_463_000), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), - EIP155Block: big.NewInt(2_675_000), - EIP158Block: big.NewInt(2_675_000), - ByzantiumBlock: big.NewInt(4_370_000), - ConstantinopleBlock: big.NewInt(7_280_000), - PetersburgBlock: big.NewInt(7_280_000), - IstanbulBlock: big.NewInt(9_069_000), - MuirGlacierBlock: big.NewInt(9_200_000), - BerlinBlock: big.NewInt(12_244_000), - LondonBlock: big.NewInt(12_965_000), - ArrowGlacierBlock: big.NewInt(13_773_000), - GrayGlacierBlock: big.NewInt(15_050_000), - TerminalTotalDifficulty: MainnetTerminalTotalDifficulty, // 58_750_000_000_000_000_000_000 - Ethash: new(EthashConfig), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(1_150_000), + DAOForkBlock: big.NewInt(1_920_000), + DAOForkSupport: true, + EIP150Block: big.NewInt(2_463_000), + EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), + EIP155Block: big.NewInt(2_675_000), + EIP158Block: big.NewInt(2_675_000), + ByzantiumBlock: big.NewInt(4_370_000), + ConstantinopleBlock: big.NewInt(7_280_000), + PetersburgBlock: big.NewInt(7_280_000), + IstanbulBlock: big.NewInt(9_069_000), + MuirGlacierBlock: big.NewInt(9_200_000), + BerlinBlock: big.NewInt(12_244_000), + LondonBlock: big.NewInt(12_965_000), + ArrowGlacierBlock: big.NewInt(13_773_000), + GrayGlacierBlock: big.NewInt(15_050_000), + TerminalTotalDifficulty: MainnetTerminalTotalDifficulty, // 58_750_000_000_000_000_000_000 + TerminalTotalDifficultyPassed: true, + Ethash: new(EthashConfig), } // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. From 69568c554880b3567bace64f8848ff1be27d084d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 15 Sep 2022 17:55:58 +0200 Subject: [PATCH 05/37] params: release Geth v1.10.25 --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/version.go b/params/version.go index 349bdf1c18d1..3b5978e849cd 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 10 // Minor version component of the current release - VersionPatch = 24 // Patch version component of the current release + VersionPatch = 25 // Patch version component of the current release VersionMeta = "stable" // Version metadata to append to the version string ) From 85e469f787be53192fcbcee86ce67635020a4ad5 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 31 Aug 2022 17:58:18 +0200 Subject: [PATCH 06/37] eth/protocols/snap: fix problems due to idle-but-busy peers (#25651) --- eth/protocols/snap/sync.go | 90 +++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index deaa4456e0fd..1455bacbcb88 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2248,14 +2248,18 @@ func (s *Syncer) OnAccounts(peer SyncPeer, id uint64, hashes []common.Hash, acco // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.accountIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.accountIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.accountReqs[id] if !ok { @@ -2360,14 +2364,18 @@ func (s *Syncer) onByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) error // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.bytecodeIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.bytecodeIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.bytecodeReqs[id] if !ok { @@ -2469,14 +2477,18 @@ func (s *Syncer) OnStorage(peer SyncPeer, id uint64, hashes [][]common.Hash, slo // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.storageIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.storageIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.storageReqs[id] if !ok { @@ -2596,14 +2608,18 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.trienodeHealIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.trienodeHealIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.trienodeHealReqs[id] if !ok { @@ -2691,14 +2707,18 @@ func (s *Syncer) onHealByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) e // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.bytecodeHealIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.bytecodeHealIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.bytecodeHealReqs[id] if !ok { From 937ea491f95e5676d2ce3e0364ba9f05452bc351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 9 Sep 2022 11:42:57 +0300 Subject: [PATCH 07/37] eth/protocols/snap: throttle trie heal requests when peers DoS us (#25666) * eth/protocols/snap: throttle trie heal requests when peers DoS us * eth/protocols/snap: lower heal throttle log to debug Co-authored-by: Martin Holst Swende * eth/protocols/snap: fix comment Co-authored-by: Martin Holst Swende --- eth/protocols/snap/sync.go | 107 ++++++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 7 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 1455bacbcb88..eb8260bf7c97 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -21,10 +21,12 @@ import ( "encoding/json" "errors" "fmt" + gomath "math" "math/big" "math/rand" "sort" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -78,6 +80,29 @@ const ( // and waste round trip times. If it's too high, we're capping responses and // waste bandwidth. maxTrieRequestCount = maxRequestSize / 512 + + // trienodeHealRateMeasurementImpact is the impact a single measurement has on + // the local node's trienode processing capacity. A value closer to 0 reacts + // slower to sudden changes, but it is also more stable against temporary hiccups. + trienodeHealRateMeasurementImpact = 0.005 + + // minTrienodeHealThrottle is the minimum divisor for throttling trie node + // heal requests to avoid overloading the local node and exessively expanding + // the state trie bedth wise. + minTrienodeHealThrottle = 1 + + // maxTrienodeHealThrottle is the maximum divisor for throttling trie node + // heal requests to avoid overloading the local node and exessively expanding + // the state trie bedth wise. + maxTrienodeHealThrottle = maxTrieRequestCount + + // trienodeHealThrottleIncrease is the multiplier for the throttle when the + // rate of arriving data is higher than the rate of processing it. + trienodeHealThrottleIncrease = 1.33 + + // trienodeHealThrottleDecrease is the divisor for the throttle when the + // rate of arriving data is lower than the rate of processing it. + trienodeHealThrottleDecrease = 1.25 ) var ( @@ -431,6 +456,11 @@ type Syncer struct { trienodeHealReqs map[uint64]*trienodeHealRequest // Trie node requests currently running bytecodeHealReqs map[uint64]*bytecodeHealRequest // Bytecode requests currently running + trienodeHealRate float64 // Average heal rate for processing trie node data + trienodeHealPend uint64 // Number of trie nodes currently pending for processing + trienodeHealThrottle float64 // Divisor for throttling the amount of trienode heal data requested + trienodeHealThrottled time.Time // Timestamp the last time the throttle was updated + trienodeHealSynced uint64 // Number of state trie nodes downloaded trienodeHealBytes common.StorageSize // Number of state trie bytes persisted to disk trienodeHealDups uint64 // Number of state trie nodes already processed @@ -476,9 +506,10 @@ func NewSyncer(db ethdb.KeyValueStore) *Syncer { trienodeHealIdlers: make(map[string]struct{}), bytecodeHealIdlers: make(map[string]struct{}), - trienodeHealReqs: make(map[uint64]*trienodeHealRequest), - bytecodeHealReqs: make(map[uint64]*bytecodeHealRequest), - stateWriter: db.NewBatch(), + trienodeHealReqs: make(map[uint64]*trienodeHealRequest), + bytecodeHealReqs: make(map[uint64]*bytecodeHealRequest), + trienodeHealThrottle: maxTrienodeHealThrottle, // Tune downward instead of insta-filling with junk + stateWriter: db.NewBatch(), extProgress: new(SyncProgress), } @@ -1321,6 +1352,10 @@ func (s *Syncer) assignTrienodeHealTasks(success chan *trienodeHealResponse, fai if cap > maxTrieRequestCount { cap = maxTrieRequestCount } + cap = int(float64(cap) / s.trienodeHealThrottle) + if cap <= 0 { + cap = 1 + } var ( hashes = make([]common.Hash, 0, cap) paths = make([]string, 0, cap) @@ -2090,6 +2125,10 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { // processTrienodeHealResponse integrates an already validated trienode response // into the healer tasks. func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { + var ( + start = time.Now() + fills int + ) for i, hash := range res.hashes { node := res.nodes[i] @@ -2098,6 +2137,8 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { res.task.trieTasks[res.paths[i]] = res.hashes[i] continue } + fills++ + // Push the trie node into the state syncer s.trienodeHealSynced++ s.trienodeHealBytes += common.StorageSize(len(node)) @@ -2121,6 +2162,50 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { log.Crit("Failed to persist healing data", "err", err) } log.Debug("Persisted set of healing data", "type", "trienodes", "bytes", common.StorageSize(batch.ValueSize())) + + // Calculate the processing rate of one filled trie node + rate := float64(fills) / (float64(time.Since(start)) / float64(time.Second)) + + // Update the currently measured trienode queueing and processing throughput. + // + // The processing rate needs to be updated uniformly independent if we've + // processed 1x100 trie nodes or 100x1 to keep the rate consistent even in + // the face of varying network packets. As such, we cannot just measure the + // time it took to process N trie nodes and update once, we need one update + // per trie node. + // + // Naively, that would be: + // + // for i:=0; i time.Second { + // Periodically adjust the trie node throttler + if float64(pending) > 2*s.trienodeHealRate { + s.trienodeHealThrottle *= trienodeHealThrottleIncrease + } else { + s.trienodeHealThrottle /= trienodeHealThrottleDecrease + } + if s.trienodeHealThrottle > maxTrienodeHealThrottle { + s.trienodeHealThrottle = maxTrienodeHealThrottle + } else if s.trienodeHealThrottle < minTrienodeHealThrottle { + s.trienodeHealThrottle = minTrienodeHealThrottle + } + s.trienodeHealThrottled = time.Now() + + log.Debug("Updated trie node heal throttler", "rate", s.trienodeHealRate, "pending", pending, "throttle", s.trienodeHealThrottle) + } } // processBytecodeHealResponse integrates an already validated bytecode response @@ -2655,10 +2740,12 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error // Cross reference the requested trienodes with the response to find gaps // that the serving node is missing - hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) - hash := make([]byte, 32) - - nodes := make([][]byte, len(req.hashes)) + var ( + hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState) + hash = make([]byte, 32) + nodes = make([][]byte, len(req.hashes)) + fills uint64 + ) for i, j := 0, 0; i < len(trienodes); i++ { // Find the next hash that we've been served, leaving misses with nils hasher.Reset() @@ -2670,16 +2757,22 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error } if j < len(req.hashes) { nodes[j] = trienodes[i] + fills++ j++ continue } // We've either ran out of hashes, or got unrequested data logger.Warn("Unexpected healing trienodes", "count", len(trienodes)-i) + // Signal this request as failed, and ready for rescheduling s.scheduleRevertTrienodeHealRequest(req) return errors.New("unexpected healing trienode") } // Response validated, send it to the scheduler for filling + atomic.AddUint64(&s.trienodeHealPend, fills) + defer func() { + atomic.AddUint64(&s.trienodeHealPend, ^(fills - 1)) + }() response := &trienodeHealResponse{ paths: req.paths, task: req.task, From a32e69a28c2abef6a6b96e8d2466f1f27fd693ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 6 Sep 2022 12:57:03 +0300 Subject: [PATCH 08/37] trie: check childrens' existence concurrently for snap heal (#25694) --- trie/sync.go | 57 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/trie/sync.go b/trie/sync.go index 303fcbfa22e2..862ce7e16e6c 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -19,6 +19,7 @@ package trie import ( "errors" "fmt" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/prque" @@ -381,11 +382,11 @@ func (s *Sync) scheduleCodeRequest(req *codeRequest) { // retrieval scheduling. func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { // Gather all the children of the node, irrelevant whether known or not - type child struct { + type childNode struct { path []byte node node } - var children []child + var children []childNode switch node := (object).(type) { case *shortNode: @@ -393,14 +394,14 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { if hasTerm(key) { key = key[:len(key)-1] } - children = []child{{ + children = []childNode{{ node: node.Val, path: append(append([]byte(nil), req.path...), key...), }} case *fullNode: for i := 0; i < 17; i++ { if node.Children[i] != nil { - children = append(children, child{ + children = append(children, childNode{ node: node.Children[i], path: append(append([]byte(nil), req.path...), byte(i)), }) @@ -410,7 +411,10 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { panic(fmt.Sprintf("unknown node: %+v", node)) } // Iterate over the children, and request all unknown ones - requests := make([]*nodeRequest, 0, len(children)) + var ( + missing = make(chan *nodeRequest, len(children)) + pending sync.WaitGroup + ) for _, child := range children { // Notify any external watcher of a new key/value node if req.callback != nil { @@ -433,19 +437,36 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { if s.membatch.hasNode(child.path) { continue } - // If database says duplicate, then at least the trie node is present - // and we hold the assumption that it's NOT legacy contract code. - chash := common.BytesToHash(node) - if rawdb.HasTrieNode(s.database, chash) { - continue - } - // Locally unknown node, schedule for retrieval - requests = append(requests, &nodeRequest{ - path: child.path, - hash: chash, - parent: req, - callback: req.callback, - }) + // Check the presence of children concurrently + pending.Add(1) + go func(child childNode) { + defer pending.Done() + + // If database says duplicate, then at least the trie node is present + // and we hold the assumption that it's NOT legacy contract code. + chash := common.BytesToHash(node) + if rawdb.HasTrieNode(s.database, chash) { + return + } + // Locally unknown node, schedule for retrieval + missing <- &nodeRequest{ + path: child.path, + hash: chash, + parent: req, + callback: req.callback, + } + }(child) + } + } + pending.Wait() + + requests := make([]*nodeRequest, 0, len(children)) + for done := false; !done; { + select { + case miss := <-missing: + requests = append(requests, miss) + default: + done = true } } return requests, nil From 99bbb337011ef614fc5d25c130aa1cef92915366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 20 Sep 2022 14:14:24 +0300 Subject: [PATCH 09/37] eth: fix a rare datarace on CHT challenge reply / shutdown (#25831) --- eth/handler.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/eth/handler.go b/eth/handler.go index 4224a9f33a84..143147b0c815 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -391,11 +391,16 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { if h.checkpointHash != (common.Hash{}) { // Request the peer's checkpoint header for chain height/weight validation resCh := make(chan *eth.Response) - if _, err := peer.RequestHeadersByNumber(h.checkpointNumber, 1, 0, false, resCh); err != nil { + + req, err := peer.RequestHeadersByNumber(h.checkpointNumber, 1, 0, false, resCh) + if err != nil { return err } // Start a timer to disconnect if the peer doesn't reply in time go func() { + // Ensure the request gets cancelled in case of error/drop + defer req.Close() + timeout := time.NewTimer(syncChallengeTimeout) defer timeout.Stop() @@ -437,10 +442,15 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { // If we have any explicit peer required block hashes, request them for number, hash := range h.requiredBlocks { resCh := make(chan *eth.Response) - if _, err := peer.RequestHeadersByNumber(number, 1, 0, false, resCh); err != nil { + + req, err := peer.RequestHeadersByNumber(number, 1, 0, false, resCh) + if err != nil { return err } - go func(number uint64, hash common.Hash) { + go func(number uint64, hash common.Hash, req *eth.Request) { + // Ensure the request gets cancelled in case of error/drop + defer req.Close() + timeout := time.NewTimer(syncChallengeTimeout) defer timeout.Stop() @@ -469,7 +479,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Warn("Required block challenge timed out, dropping", "addr", peer.RemoteAddr(), "type", peer.Name()) h.removePeer(peer.ID()) } - }(number, hash) + }(number, hash, req) } // Handle incoming messages until the connection is torn down return handler(peer) From 27600a5b8452c39ce9ef5c502c98a0c1ee35859b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 27 Oct 2022 15:25:01 +0200 Subject: [PATCH 10/37] eth/filters: change filter block to be by-ref (#26054) This PR changes the block field in the filter to be a pointer, to disambiguate between empty hash and no hash --- eth/filters/filter.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 0a70c9ece1db..8d80647fc241 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -34,8 +34,8 @@ type Filter struct { addresses []common.Address topics [][]common.Hash - block common.Hash // Block hash if filtering a single block - begin, end int64 // Range interval if filtering multiple blocks + block *common.Hash // Block hash if filtering a single block + begin, end int64 // Range interval if filtering multiple blocks matcher *bloombits.Matcher } @@ -78,7 +78,7 @@ func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Add func (sys *FilterSystem) NewBlockFilter(block common.Hash, addresses []common.Address, topics [][]common.Hash) *Filter { // Create a generic filter and convert it into a block filter filter := newFilter(sys, addresses, topics) - filter.block = block + filter.block = &block return filter } @@ -96,8 +96,8 @@ func newFilter(sys *FilterSystem, addresses []common.Address, topics [][]common. // first block that contains matches, updating the start of the filter accordingly. func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { // If we're doing singleton block filtering, execute and return - if f.block != (common.Hash{}) { - header, err := f.sys.backend.HeaderByHash(ctx, f.block) + if f.block != nil { + header, err := f.sys.backend.HeaderByHash(ctx, *f.block) if err != nil { return nil, err } From 211dbb719711420358a3cdf718ce476c212adcf5 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 2 Nov 2022 09:29:33 -0500 Subject: [PATCH 11/37] rpc: handle wrong HTTP batch response length (#26064) --- rpc/client.go | 1 + rpc/client_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++ rpc/http.go | 3 +++ 3 files changed, 52 insertions(+) diff --git a/rpc/client.go b/rpc/client.go index d3ce0297754c..fcd31319a3c5 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -31,6 +31,7 @@ import ( ) var ( + ErrBadResult = errors.New("bad result in JSON-RPC response") ErrClientQuit = errors.New("client is closed") ErrNoResult = errors.New("no result in JSON-RPC response") ErrSubscriptionQueueOverflow = errors.New("subscription queue overflow") diff --git a/rpc/client_test.go b/rpc/client_test.go index 04c847d0d626..5ae549d86533 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -19,6 +19,7 @@ package rpc import ( "context" "encoding/json" + "errors" "fmt" "math/rand" "net" @@ -144,6 +145,53 @@ func TestClientBatchRequest(t *testing.T) { } } +func TestClientBatchRequest_len(t *testing.T) { + b, err := json.Marshal([]jsonrpcMessage{ + {Version: "2.0", ID: json.RawMessage("1"), Method: "foo", Result: json.RawMessage(`"0x1"`)}, + {Version: "2.0", ID: json.RawMessage("2"), Method: "bar", Result: json.RawMessage(`"0x2"`)}, + }) + if err != nil { + t.Fatal("failed to encode jsonrpc message:", err) + } + s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + _, err := rw.Write(b) + if err != nil { + t.Error("failed to write response:", err) + } + })) + t.Cleanup(s.Close) + + client, err := Dial(s.URL) + if err != nil { + t.Fatal("failed to dial test server:", err) + } + defer client.Close() + + t.Run("too-few", func(t *testing.T) { + batch := []BatchElem{ + {Method: "foo"}, + {Method: "bar"}, + {Method: "baz"}, + } + ctx, cancelFn := context.WithTimeout(context.Background(), time.Second) + defer cancelFn() + if err := client.BatchCallContext(ctx, batch); !errors.Is(err, ErrBadResult) { + t.Errorf("expected %q but got: %v", ErrBadResult, err) + } + }) + + t.Run("too-many", func(t *testing.T) { + batch := []BatchElem{ + {Method: "foo"}, + } + ctx, cancelFn := context.WithTimeout(context.Background(), time.Second) + defer cancelFn() + if err := client.BatchCallContext(ctx, batch); !errors.Is(err, ErrBadResult) { + t.Errorf("expected %q but got: %v", ErrBadResult, err) + } + }) +} + func TestClientNotify(t *testing.T) { server := newTestServer() defer server.Stop() diff --git a/rpc/http.go b/rpc/http.go index 858d80858652..b82ea2707a54 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -173,6 +173,9 @@ func (c *Client) sendBatchHTTP(ctx context.Context, op *requestOp, msgs []*jsonr if err := json.NewDecoder(respBody).Decode(&respmsgs); err != nil { return err } + if len(respmsgs) != len(msgs) { + return fmt.Errorf("batch has %d requests but response has %d: %w", len(msgs), len(respmsgs), ErrBadResult) + } for i := 0; i < len(respmsgs); i++ { op.resp <- &respmsgs[i] } From e5eb32acee19cc9fca6a03b10283b7484246b15a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 3 Nov 2022 11:59:33 +0100 Subject: [PATCH 12/37] params: release geth v1.10.26 stable --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/version.go b/params/version.go index 3b5978e849cd..d9a3958512c3 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 10 // Minor version component of the current release - VersionPatch = 25 // Patch version component of the current release + VersionPatch = 26 // Patch version component of the current release VersionMeta = "stable" // Version metadata to append to the version string ) From 37748e5db6874bb3c886967d19d9da9ba4197249 Mon Sep 17 00:00:00 2001 From: Devon Bear Date: Mon, 16 Jan 2023 18:18:58 -0500 Subject: [PATCH 13/37] stateful --- core/vm/contracts.go | 57 +++++++++++++++++++++-------------------- core/vm/evm.go | 57 +++++++++++++++++++++++++++++------------ core/vm/instructions.go | 19 +++++++++----- go.mod | 2 -- go.sum | 34 +++--------------------- 5 files changed, 87 insertions(+), 82 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 1b832b638695..93b75fb38d34 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -36,8 +36,8 @@ import ( // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { - RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use - Run(input []byte) ([]byte, error) // Run runs the precompiled contract + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) // Run runs the precompiled contract } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum @@ -151,7 +151,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uin return nil, 0, ErrOutOfGas } suppliedGas -= gasCost - output, err := p.Run(input) + output, err := p.Run(nil, input, common.Address{}, nil, true) return output, suppliedGas, err } @@ -162,7 +162,7 @@ func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(input []byte) ([]byte, error) { +func (c *ecrecover) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { const ecRecoverInputLength = 128 input = common.RightPadBytes(input, ecRecoverInputLength) @@ -203,7 +203,7 @@ type sha256hash struct{} func (c *sha256hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas } -func (c *sha256hash) Run(input []byte) ([]byte, error) { +func (c *sha256hash) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { h := sha256.Sum256(input) return h[:], nil } @@ -218,7 +218,7 @@ type ripemd160hash struct{} func (c *ripemd160hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas } -func (c *ripemd160hash) Run(input []byte) ([]byte, error) { +func (c *ripemd160hash) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil @@ -234,8 +234,8 @@ type dataCopy struct{} func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } -func (c *dataCopy) Run(in []byte) ([]byte, error) { - return in, nil +func (c *dataCopy) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { + return input, nil } // bigModExp implements a native big integer exponential modular operation. @@ -264,9 +264,10 @@ var ( // modexpMultComplexity implements bigModexp multComplexity formula, as defined in EIP-198 // // def mult_complexity(x): -// if x <= 64: return x ** 2 -// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072 -// else: return x ** 2 // 16 + 480 * x - 199680 +// +// if x <= 64: return x ** 2 +// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072 +// else: return x ** 2 // 16 + 480 * x - 199680 // // where is x is max(length_of_MODULUS, length_of_BASE) func modexpMultComplexity(x *big.Int) *big.Int { @@ -360,7 +361,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { return gas.Uint64() } -func (c *bigModExp) Run(input []byte) ([]byte, error) { +func (c *bigModExp) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { var ( baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() @@ -433,7 +434,7 @@ func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256AddGasIstanbul } -func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256AddIstanbul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Add(input) } @@ -446,7 +447,7 @@ func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { return params.Bn256AddGasByzantium } -func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256AddByzantium) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Add(input) } @@ -471,7 +472,7 @@ func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasIstanbul } -func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256ScalarMulIstanbul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256ScalarMul(input) } @@ -484,7 +485,7 @@ func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasByzantium } -func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256ScalarMulByzantium) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256ScalarMul(input) } @@ -539,7 +540,7 @@ func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul } -func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256PairingIstanbul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Pairing(input) } @@ -552,7 +553,7 @@ func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium } -func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256PairingByzantium) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Pairing(input) } @@ -578,7 +579,7 @@ var ( errBlake2FInvalidFinalFlag = errors.New("invalid final flag") ) -func (c *blake2F) Run(input []byte) ([]byte, error) { +func (c *blake2F) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Make sure the input is valid (correct length and final flag) if len(input) != blake2FInputLength { return nil, errBlake2FInvalidInputLength @@ -632,7 +633,7 @@ func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { return params.Bls12381G1AddGas } -func (c *bls12381G1Add) Run(input []byte) ([]byte, error) { +func (c *bls12381G1Add) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1Add precompile. // > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each). // > Output is an encoding of addition operation result - single G1 point (`128` bytes). @@ -670,7 +671,7 @@ func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G1MulGas } -func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) { +func (c *bls12381G1Mul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1Mul precompile. // > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G1 point (`128` bytes). @@ -720,7 +721,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000 } -func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) { +func (c *bls12381G1MultiExp) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1MultiExp precompile. // G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes). @@ -763,7 +764,7 @@ func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { return params.Bls12381G2AddGas } -func (c *bls12381G2Add) Run(input []byte) ([]byte, error) { +func (c *bls12381G2Add) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2Add precompile. // > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each). // > Output is an encoding of addition operation result - single G2 point (`256` bytes). @@ -801,7 +802,7 @@ func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G2MulGas } -func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) { +func (c *bls12381G2Mul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2MUL precompile logic. // > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G2 point (`256` bytes). @@ -851,7 +852,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000 } -func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) { +func (c *bls12381G2MultiExp) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2MultiExp precompile logic // > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes). @@ -894,7 +895,7 @@ func (c *bls12381Pairing) RequiredGas(input []byte) uint64 { return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas } -func (c *bls12381Pairing) Run(input []byte) ([]byte, error) { +func (c *bls12381Pairing) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Pairing precompile logic. // > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure: // > - `128` bytes of G1 point encoding @@ -973,7 +974,7 @@ func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { return params.Bls12381MapG1Gas } -func (c *bls12381MapG1) Run(input []byte) ([]byte, error) { +func (c *bls12381MapG1) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_To_G1 precompile. // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. // > Output of this call is `128` bytes and is G1 point following respective encoding rules. @@ -1008,7 +1009,7 @@ func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { return params.Bls12381MapG2Gas } -func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { +func (c *bls12381MapG2) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_FP2_TO_G2 precompile logic. // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. // > Output of this call is `256` bytes and is G2 point following respective encoding rules. diff --git a/core/vm/evm.go b/core/vm/evm.go index dd55618bf812..628839c7257f 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,14 +41,22 @@ type ( GetHashFunc func(uint64) common.Hash ) -func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { +type PrecompileRegistry interface { + GetContract(addr common.Address) (PrecompiledContract, bool) +} + +type BasePrecompileRegistry struct { + chainRules params.Rules +} + +func (bpm *BasePrecompileRegistry) GetContract(addr common.Address) (PrecompiledContract, bool) { var precompiles map[common.Address]PrecompiledContract switch { - case evm.chainRules.IsBerlin: + case bpm.chainRules.IsBerlin: precompiles = PrecompiledContractsBerlin - case evm.chainRules.IsIstanbul: + case bpm.chainRules.IsIstanbul: precompiles = PrecompiledContractsIstanbul - case evm.chainRules.IsByzantium: + case bpm.chainRules.IsByzantium: precompiles = PrecompiledContractsByzantium default: precompiles = PrecompiledContractsHomestead @@ -57,6 +65,17 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { return p, ok } +func RunContract(sdb StateDB, p PrecompiledContract, input []byte, caller common.Address, + value *big.Int, suppliedGas uint64, readonly bool) (ret []byte, remainingGas uint64, err error) { + gasCost := p.RequiredGas(input) + if suppliedGas < gasCost { + return nil, 0, ErrOutOfGas + } + suppliedGas -= gasCost + output, err := p.Run(sdb, input, caller, value, readonly) + return output, suppliedGas, err +} + // BlockContext provides the EVM with auxiliary information. Once provided // it shouldn't be modified. type BlockContext struct { @@ -75,7 +94,7 @@ type BlockContext struct { Time *big.Int // Provides information for TIME Difficulty *big.Int // Provides information for DIFFICULTY BaseFee *big.Int // Provides information for BASEFEE - Random *common.Hash // Provides information for RANDOM + Random *common.Hash // Provides information for PREVRANDAO } // TxContext provides the EVM with information about a transaction. @@ -101,6 +120,8 @@ type EVM struct { TxContext // StateDB gives access to the underlying state StateDB StateDB + // PrecompileRegistry gives access to the precompiled contracts + PrecompileRegistry PrecompileRegistry // Depth is the current call stack depth int @@ -127,9 +148,12 @@ type EVM struct { // only ever be used *once*. func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { evm := &EVM{ - Context: blockCtx, - TxContext: txCtx, - StateDB: statedb, + Context: blockCtx, + TxContext: txCtx, + StateDB: statedb, + PrecompileRegistry: &BasePrecompileRegistry{ + chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), + }, Config: config, chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), @@ -175,7 +199,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - p, isPrecompile := evm.precompile(addr) + p, isPrecompile := evm.PrecompileRegistry.GetContract(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -212,7 +236,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunContract(evm.StateDB, p, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -274,8 +298,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + if p, isPrecompile := evm.PrecompileRegistry.GetContract(addr); isPrecompile { + ret, gas, err = RunContract(evm.StateDB, p, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -315,8 +339,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + if p, isPrecompile := evm.PrecompileRegistry.GetContract(addr); isPrecompile { + parent := caller.(*Contract) + ret, gas, err = RunContract(evm.StateDB, p, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -364,8 +389,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + if p, isPrecompile := evm.PrecompileRegistry.GetContract(addr); isPrecompile { + ret, gas, err = RunContract(evm.StateDB, p, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 92be3bf259a3..eacc77587a20 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -392,16 +392,21 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // opExtCodeHash returns the code hash of a specified account. // There are several cases when the function is called, while we can relay everything // to `state.GetCodeHash` function to ensure the correctness. -// (1) Caller tries to get the code hash of a normal contract account, state +// +// (1) Caller tries to get the code hash of a normal contract account, state +// // should return the relative code hash and set it as the result. // -// (2) Caller tries to get the code hash of a non-existent account, state should +// (2) Caller tries to get the code hash of a non-existent account, state should +// // return common.Hash{} and zero will be set as the result. // -// (3) Caller tries to get the code hash for an account without contract code, +// (3) Caller tries to get the code hash for an account without contract code, +// // state should return emptyCodeHash(0xc5d246...) as the result. // -// (4) Caller tries to get the code hash of a precompiled account, the result +// (4) Caller tries to get the code hash of a precompiled account, the result +// // should be zero or emptyCodeHash. // // It is worth noting that in order to avoid unnecessary create and clean, @@ -410,10 +415,12 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // If the precompile account is not transferred any amount on a private or // customized chain, the return value will be zero. // -// (5) Caller tries to get the code hash for an account which is marked as suicided +// (5) Caller tries to get the code hash for an account which is marked as suicided +// // in the current transaction, the code hash of this account should be returned. // -// (6) Caller tries to get the code hash for an account which is marked as deleted, +// (6) Caller tries to get the code hash for an account which is marked as deleted, +// // this account should be regarded as a non-existent account and zero should be returned. func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() diff --git a/go.mod b/go.mod index 4a769c7a2dca..db292bb00999 100644 --- a/go.mod +++ b/go.mod @@ -82,11 +82,9 @@ require ( github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect - github.com/go-logfmt/logfmt v0.4.0 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect - github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect diff --git a/go.sum b/go.sum index 4b27867fbc79..8686cbcd2e6a 100644 --- a/go.sum +++ b/go.sum @@ -127,9 +127,8 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlK github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= @@ -156,7 +155,6 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -204,7 +202,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -231,7 +228,6 @@ github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8= @@ -320,29 +316,19 @@ github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hz github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= @@ -408,14 +394,8 @@ github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= -github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= @@ -509,11 +489,9 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -560,7 +538,6 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -569,8 +546,6 @@ golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -618,7 +593,6 @@ golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= From cdf5821f6fa56faae77e19c6fa62ce9529c5d0d9 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 18 Jan 2023 11:57:21 -0500 Subject: [PATCH 14/37] use PrecompileExecutor --- core/vm/contracts.go | 15 --------- core/vm/evm.go | 80 +++++++++++++++----------------------------- 2 files changed, 27 insertions(+), 68 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 93b75fb38d34..fbce62a56613 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -140,21 +140,6 @@ func ActivePrecompiles(rules params.Rules) []common.Address { } } -// RunPrecompiledContract runs and evaluates the output of a precompiled contract. -// It returns -// - the returned bytes, -// - the _remaining_ gas, -// - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { - gasCost := p.RequiredGas(input) - if suppliedGas < gasCost { - return nil, 0, ErrOutOfGas - } - suppliedGas -= gasCost - output, err := p.Run(nil, input, common.Address{}, nil, true) - return output, suppliedGas, err -} - // ECRECOVER implemented as a native contract. type ecrecover struct{} diff --git a/core/vm/evm.go b/core/vm/evm.go index 628839c7257f..6705a675b914 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,39 +41,15 @@ type ( GetHashFunc func(uint64) common.Hash ) -type PrecompileRegistry interface { - GetContract(addr common.Address) (PrecompiledContract, bool) -} - -type BasePrecompileRegistry struct { - chainRules params.Rules -} - -func (bpm *BasePrecompileRegistry) GetContract(addr common.Address) (PrecompiledContract, bool) { - var precompiles map[common.Address]PrecompiledContract - switch { - case bpm.chainRules.IsBerlin: - precompiles = PrecompiledContractsBerlin - case bpm.chainRules.IsIstanbul: - precompiles = PrecompiledContractsIstanbul - case bpm.chainRules.IsByzantium: - precompiles = PrecompiledContractsByzantium - default: - precompiles = PrecompiledContractsHomestead - } - p, ok := precompiles[addr] - return p, ok -} - -func RunContract(sdb StateDB, p PrecompiledContract, input []byte, caller common.Address, - value *big.Int, suppliedGas uint64, readonly bool) (ret []byte, remainingGas uint64, err error) { - gasCost := p.RequiredGas(input) - if suppliedGas < gasCost { - return nil, 0, ErrOutOfGas - } - suppliedGas -= gasCost - output, err := p.Run(sdb, input, caller, value, readonly) - return output, suppliedGas, err +// `PrecompileExecutor` is allows the EVM to execute a precompiled contract. +type PrecompileExecutor interface { + // `Exists` returns if a precompiled contract was found at `addr`. + Exists(addr common.Address) bool + + // `Run` runs a precompiled contract and returns the leftover gas. + Run(sdb StateDB, input []byte, caller common.Address, + value *big.Int, suppliedGas uint64, readonly bool, + ) (ret []byte, leftOverGas uint64, err error) } // BlockContext provides the EVM with auxiliary information. Once provided @@ -120,8 +96,8 @@ type EVM struct { TxContext // StateDB gives access to the underlying state StateDB StateDB - // PrecompileRegistry gives access to the precompiled contracts - PrecompileRegistry PrecompileRegistry + // precompileExecutor gives access to the precompiled contracts + precompileExecutor PrecompileExecutor // Depth is the current call stack depth int @@ -146,17 +122,15 @@ type EVM struct { // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { +func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileExecutor PrecompileExecutor) *EVM { evm := &EVM{ - Context: blockCtx, - TxContext: txCtx, - StateDB: statedb, - PrecompileRegistry: &BasePrecompileRegistry{ - chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), - }, - Config: config, - chainConfig: chainConfig, - chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), + Context: blockCtx, + TxContext: txCtx, + StateDB: statedb, + precompileExecutor: precompileExecutor, + Config: config, + chainConfig: chainConfig, + chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), } evm.interpreter = NewEVMInterpreter(evm, config) return evm @@ -199,7 +173,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - p, isPrecompile := evm.PrecompileRegistry.GetContract(addr) + isPrecompile := evm.precompileExecutor.Exists(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -236,7 +210,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = RunContract(evm.StateDB, p, input, caller.Address(), value, gas, false) + ret, gas, err = evm.precompileExecutor.Run(evm.StateDB, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -298,8 +272,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.PrecompileRegistry.GetContract(addr); isPrecompile { - ret, gas, err = RunContract(evm.StateDB, p, input, caller.Address(), value, gas, true) + if evm.precompileExecutor.Exists(addr) { + ret, gas, err = evm.precompileExecutor.Run(evm.StateDB, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -339,9 +313,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.PrecompileRegistry.GetContract(addr); isPrecompile { + if evm.precompileExecutor.Exists(addr) { parent := caller.(*Contract) - ret, gas, err = RunContract(evm.StateDB, p, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.precompileExecutor.Run(evm.StateDB, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -389,8 +363,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if p, isPrecompile := evm.PrecompileRegistry.GetContract(addr); isPrecompile { - ret, gas, err = RunContract(evm.StateDB, p, input, caller.Address(), new(big.Int), gas, true) + if evm.precompileExecutor.Exists(addr) { + ret, gas, err = evm.precompileExecutor.Run(evm.StateDB, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From 2def4f08d7197fd1f219c6343efdfcc3a34cf3f0 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 18 Jan 2023 12:15:01 -0500 Subject: [PATCH 15/37] use host terminology --- core/vm/evm.go | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 6705a675b914..64f469701cf6 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,15 +41,15 @@ type ( GetHashFunc func(uint64) common.Hash ) -// `PrecompileExecutor` is allows the EVM to execute a precompiled contract. -type PrecompileExecutor interface { +// `PrecompileHost` is allows the EVM to execute a precompiled contract. +type PrecompileHost interface { // `Exists` returns if a precompiled contract was found at `addr`. Exists(addr common.Address) bool // `Run` runs a precompiled contract and returns the leftover gas. Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, suppliedGas uint64, readonly bool, - ) (ret []byte, leftOverGas uint64, err error) + ) (ret []byte, remainingGas uint64, err error) } // BlockContext provides the EVM with auxiliary information. Once provided @@ -96,8 +96,8 @@ type EVM struct { TxContext // StateDB gives access to the underlying state StateDB StateDB - // precompileExecutor gives access to the precompiled contracts - precompileExecutor PrecompileExecutor + // precompileHost gives access to the precompiled contracts + precompileHost PrecompileHost // Depth is the current call stack depth int @@ -122,15 +122,15 @@ type EVM struct { // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileExecutor PrecompileExecutor) *EVM { +func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileHost PrecompileHost) *EVM { evm := &EVM{ - Context: blockCtx, - TxContext: txCtx, - StateDB: statedb, - precompileExecutor: precompileExecutor, - Config: config, - chainConfig: chainConfig, - chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), + Context: blockCtx, + TxContext: txCtx, + StateDB: statedb, + precompileHost: precompileHost, + Config: config, + chainConfig: chainConfig, + chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), } evm.interpreter = NewEVMInterpreter(evm, config) return evm @@ -173,7 +173,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - isPrecompile := evm.precompileExecutor.Exists(addr) + isPrecompile := evm.precompileHost.Exists(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -210,7 +210,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.precompileExecutor.Run(evm.StateDB, input, caller.Address(), value, gas, false) + ret, gas, err = evm.precompileHost.Run(evm.StateDB, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -272,8 +272,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if evm.precompileExecutor.Exists(addr) { - ret, gas, err = evm.precompileExecutor.Run(evm.StateDB, input, caller.Address(), value, gas, true) + if evm.precompileHost.Exists(addr) { + ret, gas, err = evm.precompileHost.Run(evm.StateDB, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -313,9 +313,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if evm.precompileExecutor.Exists(addr) { + if evm.precompileHost.Exists(addr) { parent := caller.(*Contract) - ret, gas, err = evm.precompileExecutor.Run(evm.StateDB, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.precompileHost.Run(evm.StateDB, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -363,8 +363,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if evm.precompileExecutor.Exists(addr) { - ret, gas, err = evm.precompileExecutor.Run(evm.StateDB, input, caller.Address(), new(big.Int), gas, true) + if evm.precompileHost.Exists(addr) { + ret, gas, err = evm.precompileHost.Run(evm.StateDB, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From b7ecb9efd6c3df1b76f9773b6d630c29fb5e496a Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 18 Jan 2023 13:38:06 -0500 Subject: [PATCH 16/37] return precompiledContract and bool --- core/vm/evm.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 64f469701cf6..b7f1f9a40e89 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -44,10 +44,10 @@ type ( // `PrecompileHost` is allows the EVM to execute a precompiled contract. type PrecompileHost interface { // `Exists` returns if a precompiled contract was found at `addr`. - Exists(addr common.Address) bool + Exists(addr common.Address) (PrecompiledContract, bool) // `Run` runs a precompiled contract and returns the leftover gas. - Run(sdb StateDB, input []byte, caller common.Address, + Run(p PrecompiledContract, sdb StateDB, input []byte, caller common.Address, value *big.Int, suppliedGas uint64, readonly bool, ) (ret []byte, remainingGas uint64, err error) } @@ -173,7 +173,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - isPrecompile := evm.precompileHost.Exists(addr) + p, isPrecompile := evm.precompileHost.Exists(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -210,7 +210,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.precompileHost.Run(evm.StateDB, input, caller.Address(), value, gas, false) + ret, gas, err = evm.precompileHost.Run(p, evm.StateDB, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -272,8 +272,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if evm.precompileHost.Exists(addr) { - ret, gas, err = evm.precompileHost.Run(evm.StateDB, input, caller.Address(), value, gas, true) + if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { + ret, gas, err = evm.precompileHost.Run(p, evm.StateDB, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -313,9 +313,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if evm.precompileHost.Exists(addr) { + if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { parent := caller.(*Contract) - ret, gas, err = evm.precompileHost.Run(evm.StateDB, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.precompileHost.Run(p, evm.StateDB, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -363,8 +363,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if evm.precompileHost.Exists(addr) { - ret, gas, err = evm.precompileHost.Run(evm.StateDB, input, caller.Address(), new(big.Int), gas, true) + if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { + ret, gas, err = evm.precompileHost.Run(p, evm.StateDB, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From d1c5ff3ddf0ddf58740e28ed3f5d535e2f8f9d14 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 18 Jan 2023 13:52:25 -0500 Subject: [PATCH 17/37] use ctx in Run instead of statedb --- core/vm/contracts.go | 47 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index fbce62a56613..d1fadab1b3cc 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -17,6 +17,7 @@ package vm import ( + "context" "crypto/sha256" "encoding/binary" "errors" @@ -36,8 +37,8 @@ import ( // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { - RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use - Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) // Run runs the precompiled contract + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) // Run runs the precompiled contract } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum @@ -147,7 +148,7 @@ func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *ecrecover) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { const ecRecoverInputLength = 128 input = common.RightPadBytes(input, ecRecoverInputLength) @@ -188,7 +189,7 @@ type sha256hash struct{} func (c *sha256hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas } -func (c *sha256hash) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *sha256hash) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { h := sha256.Sum256(input) return h[:], nil } @@ -203,7 +204,7 @@ type ripemd160hash struct{} func (c *ripemd160hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas } -func (c *ripemd160hash) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *ripemd160hash) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil @@ -219,7 +220,7 @@ type dataCopy struct{} func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } -func (c *dataCopy) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *dataCopy) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return input, nil } @@ -346,7 +347,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { return gas.Uint64() } -func (c *bigModExp) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bigModExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { var ( baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() @@ -419,7 +420,7 @@ func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256AddGasIstanbul } -func (c *bn256AddIstanbul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256AddIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Add(input) } @@ -432,7 +433,7 @@ func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { return params.Bn256AddGasByzantium } -func (c *bn256AddByzantium) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256AddByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Add(input) } @@ -457,7 +458,7 @@ func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasIstanbul } -func (c *bn256ScalarMulIstanbul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256ScalarMul(input) } @@ -470,7 +471,7 @@ func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasByzantium } -func (c *bn256ScalarMulByzantium) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256ScalarMulByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256ScalarMul(input) } @@ -525,7 +526,7 @@ func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul } -func (c *bn256PairingIstanbul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256PairingIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Pairing(input) } @@ -538,7 +539,7 @@ func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium } -func (c *bn256PairingByzantium) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256PairingByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Pairing(input) } @@ -564,7 +565,7 @@ var ( errBlake2FInvalidFinalFlag = errors.New("invalid final flag") ) -func (c *blake2F) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *blake2F) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Make sure the input is valid (correct length and final flag) if len(input) != blake2FInputLength { return nil, errBlake2FInvalidInputLength @@ -618,7 +619,7 @@ func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { return params.Bls12381G1AddGas } -func (c *bls12381G1Add) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1Add) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1Add precompile. // > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each). // > Output is an encoding of addition operation result - single G1 point (`128` bytes). @@ -656,7 +657,7 @@ func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G1MulGas } -func (c *bls12381G1Mul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1Mul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1Mul precompile. // > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G1 point (`128` bytes). @@ -706,7 +707,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000 } -func (c *bls12381G1MultiExp) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1MultiExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1MultiExp precompile. // G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes). @@ -749,7 +750,7 @@ func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { return params.Bls12381G2AddGas } -func (c *bls12381G2Add) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2Add) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2Add precompile. // > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each). // > Output is an encoding of addition operation result - single G2 point (`256` bytes). @@ -787,7 +788,7 @@ func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G2MulGas } -func (c *bls12381G2Mul) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2Mul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2MUL precompile logic. // > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G2 point (`256` bytes). @@ -837,7 +838,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000 } -func (c *bls12381G2MultiExp) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2MultiExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2MultiExp precompile logic // > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes). @@ -880,7 +881,7 @@ func (c *bls12381Pairing) RequiredGas(input []byte) uint64 { return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas } -func (c *bls12381Pairing) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381Pairing) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Pairing precompile logic. // > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure: // > - `128` bytes of G1 point encoding @@ -959,7 +960,7 @@ func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { return params.Bls12381MapG1Gas } -func (c *bls12381MapG1) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381MapG1) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_To_G1 precompile. // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. // > Output of this call is `128` bytes and is G1 point following respective encoding rules. @@ -994,7 +995,7 @@ func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { return params.Bls12381MapG2Gas } -func (c *bls12381MapG2) Run(sdb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381MapG2) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_FP2_TO_G2 precompile logic. // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. // > Output of this call is `256` bytes and is G2 point following respective encoding rules. From 12579d823bbb28d0306dc1c4b9e5c691a77fc5ee Mon Sep 17 00:00:00 2001 From: Devon Bear Date: Thu, 19 Jan 2023 13:45:13 -0500 Subject: [PATCH 18/37] change to ph --- accounts/abi/bind/bind.go | 2 +- core/vm/evm.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index dac43f70e234..46bc31185f0c 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -190,7 +190,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] } eventIdentifiers[normalizedName] = true normalized.Name = normalizedName - + used := make(map[string]bool) normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) diff --git a/core/vm/evm.go b/core/vm/evm.go index b7f1f9a40e89..ce83251a8684 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -47,7 +47,7 @@ type PrecompileHost interface { Exists(addr common.Address) (PrecompiledContract, bool) // `Run` runs a precompiled contract and returns the leftover gas. - Run(p PrecompiledContract, sdb StateDB, input []byte, caller common.Address, + Run(p PrecompiledContract, input []byte, caller common.Address, value *big.Int, suppliedGas uint64, readonly bool, ) (ret []byte, remainingGas uint64, err error) } @@ -210,7 +210,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.precompileHost.Run(p, evm.StateDB, input, caller.Address(), value, gas, false) + ret, gas, err = evm.precompileHost.Run(p, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -273,7 +273,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { - ret, gas, err = evm.precompileHost.Run(p, evm.StateDB, input, caller.Address(), value, gas, true) + ret, gas, err = evm.precompileHost.Run(p, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -315,7 +315,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { parent := caller.(*Contract) - ret, gas, err = evm.precompileHost.Run(p, evm.StateDB, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.precompileHost.Run(p, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -364,7 +364,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte } if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { - ret, gas, err = evm.precompileHost.Run(p, evm.StateDB, input, caller.Address(), new(big.Int), gas, true) + ret, gas, err = evm.precompileHost.Run(p, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From f1ef333979feb23db3b82568ee01f6e370ea5f71 Mon Sep 17 00:00:00 2001 From: Devon Bear Date: Thu, 19 Jan 2023 18:35:22 -0500 Subject: [PATCH 19/37] bing bong --- core/vm/evm.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index ce83251a8684..b9e2e791196a 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -122,20 +122,25 @@ type EVM struct { // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileHost PrecompileHost) *EVM { +func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { evm := &EVM{ - Context: blockCtx, - TxContext: txCtx, - StateDB: statedb, - precompileHost: precompileHost, - Config: config, - chainConfig: chainConfig, - chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), + Context: blockCtx, + TxContext: txCtx, + StateDB: statedb, + Config: config, + chainConfig: chainConfig, + chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), } evm.interpreter = NewEVMInterpreter(evm, config) return evm } +func NewEVMWithPrecompileHost(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileHost PrecompileHost) *EVM { + evm := NewEVM(blockCtx, txCtx, statedb, chainConfig, config) + evm.precompileHost = precompileHost + return evm +} + // Reset resets the EVM with a new transaction context.Reset // This is not threadsafe and should only be done very cautiously. func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { From e604f74112846712688282dc342a9e8c40a5ba92 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Mon, 23 Jan 2023 14:43:24 -0500 Subject: [PATCH 20/37] rename to runner --- core/vm/evm.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index b9e2e791196a..b425e65d5c7d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,8 +41,8 @@ type ( GetHashFunc func(uint64) common.Hash ) -// `PrecompileHost` is allows the EVM to execute a precompiled contract. -type PrecompileHost interface { +// `PrecompileRunner` is allows the EVM to execute a precompiled contract. +type PrecompileRunner interface { // `Exists` returns if a precompiled contract was found at `addr`. Exists(addr common.Address) (PrecompiledContract, bool) @@ -96,8 +96,8 @@ type EVM struct { TxContext // StateDB gives access to the underlying state StateDB StateDB - // precompileHost gives access to the precompiled contracts - precompileHost PrecompileHost + // precompileRunner gives access to the precompiled contracts + precompileRunner PrecompileRunner // Depth is the current call stack depth int @@ -135,9 +135,9 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig return evm } -func NewEVMWithPrecompileHost(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileHost PrecompileHost) *EVM { +func NewEVMWithPrecompileHost(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileRunner PrecompileRunner) *EVM { evm := NewEVM(blockCtx, txCtx, statedb, chainConfig, config) - evm.precompileHost = precompileHost + evm.precompileRunner = precompileRunner return evm } @@ -178,7 +178,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - p, isPrecompile := evm.precompileHost.Exists(addr) + p, isPrecompile := evm.precompileRunner.Exists(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -215,7 +215,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.precompileHost.Run(p, input, caller.Address(), value, gas, false) + ret, gas, err = evm.precompileRunner.Run(p, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -277,8 +277,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { - ret, gas, err = evm.precompileHost.Run(p, input, caller.Address(), value, gas, true) + if p, isPrecompile := evm.precompileRunner.Exists(addr); isPrecompile { + ret, gas, err = evm.precompileRunner.Run(p, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -318,9 +318,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { + if p, isPrecompile := evm.precompileRunner.Exists(addr); isPrecompile { parent := caller.(*Contract) - ret, gas, err = evm.precompileHost.Run(p, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.precompileRunner.Run(p, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -368,8 +368,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if p, isPrecompile := evm.precompileHost.Exists(addr); isPrecompile { - ret, gas, err = evm.precompileHost.Run(p, input, caller.Address(), new(big.Int), gas, true) + if p, isPrecompile := evm.precompileRunner.Exists(addr); isPrecompile { + ret, gas, err = evm.precompileRunner.Run(p, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From 6dfd7b1c0c5d5371ba22e25cbd2a576287972175 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Mon, 23 Jan 2023 14:52:37 -0500 Subject: [PATCH 21/37] rename constructor --- core/vm/evm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index b425e65d5c7d..027218c894ff 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -135,7 +135,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig return evm } -func NewEVMWithPrecompileHost(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileRunner PrecompileRunner) *EVM { +func NewEVMWithPrecompiles(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileRunner PrecompileRunner) *EVM { evm := NewEVM(blockCtx, txCtx, statedb, chainConfig, config) evm.precompileRunner = precompileRunner return evm From 6b58c1d41d7177175e3de1938a6acc465d40a6d7 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Tue, 24 Jan 2023 12:54:21 -0500 Subject: [PATCH 22/37] new precompile function types --- core/vm/evm.go | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 027218c894ff..a8d1b05f7429 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,16 +41,14 @@ type ( GetHashFunc func(uint64) common.Hash ) -// `PrecompileRunner` is allows the EVM to execute a precompiled contract. -type PrecompileRunner interface { - // `Exists` returns if a precompiled contract was found at `addr`. - Exists(addr common.Address) (PrecompiledContract, bool) - - // `Run` runs a precompiled contract and returns the leftover gas. - Run(p PrecompiledContract, input []byte, caller common.Address, - value *big.Int, suppliedGas uint64, readonly bool, - ) (ret []byte, remainingGas uint64, err error) -} +// `PrecompileExists` returns if a precompiled contract was found at `addr`. +type PrecompileExists func(addr common.Address) (p PrecompiledContract, found bool) + +// `RunPrecompile` runs a precompiled contract and returns the remaining gas. +type RunPrecompile func( + p PrecompiledContract, input []byte, caller common.Address, + value *big.Int, suppliedGas uint64, readonly bool, +) (ret []byte, remainingGas uint64, err error) // BlockContext provides the EVM with auxiliary information. Once provided // it shouldn't be modified. @@ -96,8 +94,11 @@ type EVM struct { TxContext // StateDB gives access to the underlying state StateDB StateDB - // precompileRunner gives access to the precompiled contracts - precompileRunner PrecompileRunner + // precompileExists searches an address for a precompiled + // contract + precompileExists PrecompileExists + // runPrecompile gives access running a precompiled contract + runPrecompile RunPrecompile // Depth is the current call stack depth int @@ -135,9 +136,13 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig return evm } -func NewEVMWithPrecompiles(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, precompileRunner PrecompileRunner) *EVM { +func NewEVMWithPrecompiles( + blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, + config Config, precompileExists PrecompileExists, runPrecompile RunPrecompile, +) *EVM { evm := NewEVM(blockCtx, txCtx, statedb, chainConfig, config) - evm.precompileRunner = precompileRunner + evm.precompileExists = precompileExists + evm.runPrecompile = runPrecompile return evm } @@ -178,7 +183,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - p, isPrecompile := evm.precompileRunner.Exists(addr) + p, isPrecompile := evm.precompileExists(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -215,7 +220,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.precompileRunner.Run(p, input, caller.Address(), value, gas, false) + ret, gas, err = evm.runPrecompile(p, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -277,8 +282,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompileRunner.Exists(addr); isPrecompile { - ret, gas, err = evm.precompileRunner.Run(p, input, caller.Address(), value, gas, true) + if p, isPrecompile := evm.precompileExists(addr); isPrecompile { + ret, gas, err = evm.runPrecompile(p, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -318,9 +323,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompileRunner.Exists(addr); isPrecompile { + if p, isPrecompile := evm.precompileExists(addr); isPrecompile { parent := caller.(*Contract) - ret, gas, err = evm.precompileRunner.Run(p, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.runPrecompile(p, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -368,8 +373,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if p, isPrecompile := evm.precompileRunner.Exists(addr); isPrecompile { - ret, gas, err = evm.precompileRunner.Run(p, input, caller.Address(), new(big.Int), gas, true) + if p, isPrecompile := evm.precompileExists(addr); isPrecompile { + ret, gas, err = evm.runPrecompile(p, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From 8f77e9a6b0383ffce433654dbe59b9e5d78c6dde Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Tue, 24 Jan 2023 14:46:22 -0500 Subject: [PATCH 23/37] precompile controller --- core/vm/evm.go | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index a8d1b05f7429..00ff2729491a 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,14 +41,16 @@ type ( GetHashFunc func(uint64) common.Hash ) -// `PrecompileExists` returns if a precompiled contract was found at `addr`. -type PrecompileExists func(addr common.Address) (p PrecompiledContract, found bool) - -// `RunPrecompile` runs a precompiled contract and returns the remaining gas. -type RunPrecompile func( - p PrecompiledContract, input []byte, caller common.Address, - value *big.Int, suppliedGas uint64, readonly bool, -) (ret []byte, remainingGas uint64, err error) +// `PrecompileController` allows the EVM to execute a precompiled contract. +type PrecompileController interface { + // `Exists` returns if a precompiled contract was found at `addr`. + Exists(addr common.Address) (p PrecompiledContract, found bool) + + // `Run` runs a precompiled contract and returns the remaining gas. + Run(p PrecompiledContract, input []byte, caller common.Address, + value *big.Int, suppliedGas uint64, readonly bool, + ) (ret []byte, remainingGas uint64, err error) +} // BlockContext provides the EVM with auxiliary information. Once provided // it shouldn't be modified. @@ -94,11 +96,8 @@ type EVM struct { TxContext // StateDB gives access to the underlying state StateDB StateDB - // precompileExists searches an address for a precompiled - // contract - precompileExists PrecompileExists - // runPrecompile gives access running a precompiled contract - runPrecompile RunPrecompile + // precompileController finds and runs precompiled contracts + precompileController PrecompileController // Depth is the current call stack depth int @@ -137,12 +136,11 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig } func NewEVMWithPrecompiles( - blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, - config Config, precompileExists PrecompileExists, runPrecompile RunPrecompile, + blockCtx BlockContext, txCtx TxContext, statedb StateDB, + chainConfig *params.ChainConfig, config Config, precompileController PrecompileController, ) *EVM { evm := NewEVM(blockCtx, txCtx, statedb, chainConfig, config) - evm.precompileExists = precompileExists - evm.runPrecompile = runPrecompile + evm.precompileController = precompileController return evm } @@ -183,7 +181,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - p, isPrecompile := evm.precompileExists(addr) + p, isPrecompile := evm.precompileController.Exists(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -220,7 +218,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.runPrecompile(p, input, caller.Address(), value, gas, false) + ret, gas, err = evm.precompileController.Run(p, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -282,8 +280,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompileExists(addr); isPrecompile { - ret, gas, err = evm.runPrecompile(p, input, caller.Address(), value, gas, true) + if p, isPrecompile := evm.precompileController.Exists(addr); isPrecompile { + ret, gas, err = evm.precompileController.Run(p, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -323,9 +321,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompileExists(addr); isPrecompile { + if p, isPrecompile := evm.precompileController.Exists(addr); isPrecompile { parent := caller.(*Contract) - ret, gas, err = evm.runPrecompile(p, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.precompileController.Run(p, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -373,8 +371,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if p, isPrecompile := evm.precompileExists(addr); isPrecompile { - ret, gas, err = evm.runPrecompile(p, input, caller.Address(), new(big.Int), gas, true) + if p, isPrecompile := evm.precompileController.Exists(addr); isPrecompile { + ret, gas, err = evm.precompileController.Run(p, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From eca0bbbbabc5308e4829ddad39ea55dd457c6828 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 25 Jan 2023 13:43:24 -0500 Subject: [PATCH 24/37] make PrecompileController public --- core/vm/evm.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 00ff2729491a..335c0726a821 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -96,8 +96,8 @@ type EVM struct { TxContext // StateDB gives access to the underlying state StateDB StateDB - // precompileController finds and runs precompiled contracts - precompileController PrecompileController + // PrecompileController finds and runs precompiled contracts + PrecompileController PrecompileController // Depth is the current call stack depth int @@ -140,7 +140,7 @@ func NewEVMWithPrecompiles( chainConfig *params.ChainConfig, config Config, precompileController PrecompileController, ) *EVM { evm := NewEVM(blockCtx, txCtx, statedb, chainConfig, config) - evm.precompileController = precompileController + evm.PrecompileController = precompileController return evm } @@ -181,7 +181,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - p, isPrecompile := evm.precompileController.Exists(addr) + p, isPrecompile := evm.PrecompileController.Exists(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -218,7 +218,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.precompileController.Run(p, input, caller.Address(), value, gas, false) + ret, gas, err = evm.PrecompileController.Run(p, input, caller.Address(), value, gas, false) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -280,8 +280,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompileController.Exists(addr); isPrecompile { - ret, gas, err = evm.precompileController.Run(p, input, caller.Address(), value, gas, true) + if p, isPrecompile := evm.PrecompileController.Exists(addr); isPrecompile { + ret, gas, err = evm.PrecompileController.Run(p, input, caller.Address(), value, gas, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -321,9 +321,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompileController.Exists(addr); isPrecompile { + if p, isPrecompile := evm.PrecompileController.Exists(addr); isPrecompile { parent := caller.(*Contract) - ret, gas, err = evm.precompileController.Run(p, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.PrecompileController.Run(p, input, parent.CallerAddress, parent.value, gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -371,8 +371,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if p, isPrecompile := evm.precompileController.Exists(addr); isPrecompile { - ret, gas, err = evm.precompileController.Run(p, input, caller.Address(), new(big.Int), gas, true) + if p, isPrecompile := evm.PrecompileController.Exists(addr); isPrecompile { + ret, gas, err = evm.PrecompileController.Run(p, input, caller.Address(), new(big.Int), gas, true) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From cdf3a3943650f380c14b946f34f73b816205f2ae Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 25 Jan 2023 14:17:25 -0500 Subject: [PATCH 25/37] ctx setter --- core/vm/evm.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/vm/evm.go b/core/vm/evm.go index 335c0726a821..0b580e47bced 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -17,6 +17,7 @@ package vm import ( + "context" "math/big" "sync/atomic" "time" @@ -43,6 +44,9 @@ type ( // `PrecompileController` allows the EVM to execute a precompiled contract. type PrecompileController interface { + // `SetEphemeralContext` sets the precompile's native environment context. + SetEphemeralContext(ctx context.Context) + // `Exists` returns if a precompiled contract was found at `addr`. Exists(addr common.Address) (p PrecompiledContract, found bool) From dc459cd07e42694777173e1433d78af816ee620f Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 25 Jan 2023 14:28:01 -0500 Subject: [PATCH 26/37] add statedb in contract.Run --- core/vm/contracts.go | 46 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index d1fadab1b3cc..6c4e91f02dc1 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -37,8 +37,8 @@ import ( // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { - RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use - Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) // Run runs the precompiled contract + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) // Run runs the precompiled contract } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum @@ -148,7 +148,7 @@ func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *ecrecover) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { const ecRecoverInputLength = 128 input = common.RightPadBytes(input, ecRecoverInputLength) @@ -189,7 +189,7 @@ type sha256hash struct{} func (c *sha256hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas } -func (c *sha256hash) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *sha256hash) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { h := sha256.Sum256(input) return h[:], nil } @@ -204,7 +204,7 @@ type ripemd160hash struct{} func (c *ripemd160hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas } -func (c *ripemd160hash) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *ripemd160hash) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil @@ -220,7 +220,7 @@ type dataCopy struct{} func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } -func (c *dataCopy) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *dataCopy) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return input, nil } @@ -347,7 +347,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { return gas.Uint64() } -func (c *bigModExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bigModExp) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { var ( baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() @@ -420,7 +420,7 @@ func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256AddGasIstanbul } -func (c *bn256AddIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256AddIstanbul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Add(input) } @@ -433,7 +433,7 @@ func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { return params.Bn256AddGasByzantium } -func (c *bn256AddByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256AddByzantium) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Add(input) } @@ -458,7 +458,7 @@ func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasIstanbul } -func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256ScalarMul(input) } @@ -471,7 +471,7 @@ func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasByzantium } -func (c *bn256ScalarMulByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256ScalarMulByzantium) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256ScalarMul(input) } @@ -526,7 +526,7 @@ func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul } -func (c *bn256PairingIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256PairingIstanbul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Pairing(input) } @@ -539,7 +539,7 @@ func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium } -func (c *bn256PairingByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256PairingByzantium) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Pairing(input) } @@ -565,7 +565,7 @@ var ( errBlake2FInvalidFinalFlag = errors.New("invalid final flag") ) -func (c *blake2F) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *blake2F) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Make sure the input is valid (correct length and final flag) if len(input) != blake2FInputLength { return nil, errBlake2FInvalidInputLength @@ -619,7 +619,7 @@ func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { return params.Bls12381G1AddGas } -func (c *bls12381G1Add) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1Add) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1Add precompile. // > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each). // > Output is an encoding of addition operation result - single G1 point (`128` bytes). @@ -657,7 +657,7 @@ func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G1MulGas } -func (c *bls12381G1Mul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1Mul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1Mul precompile. // > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G1 point (`128` bytes). @@ -707,7 +707,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000 } -func (c *bls12381G1MultiExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1MultiExp) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1MultiExp precompile. // G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes). @@ -750,7 +750,7 @@ func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { return params.Bls12381G2AddGas } -func (c *bls12381G2Add) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2Add) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2Add precompile. // > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each). // > Output is an encoding of addition operation result - single G2 point (`256` bytes). @@ -788,7 +788,7 @@ func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G2MulGas } -func (c *bls12381G2Mul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2Mul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2MUL precompile logic. // > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G2 point (`256` bytes). @@ -838,7 +838,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000 } -func (c *bls12381G2MultiExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2MultiExp) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2MultiExp precompile logic // > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes). @@ -881,7 +881,7 @@ func (c *bls12381Pairing) RequiredGas(input []byte) uint64 { return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas } -func (c *bls12381Pairing) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381Pairing) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Pairing precompile logic. // > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure: // > - `128` bytes of G1 point encoding @@ -960,7 +960,7 @@ func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { return params.Bls12381MapG1Gas } -func (c *bls12381MapG1) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381MapG1) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_To_G1 precompile. // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. // > Output of this call is `128` bytes and is G1 point following respective encoding rules. @@ -995,7 +995,7 @@ func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { return params.Bls12381MapG2Gas } -func (c *bls12381MapG2) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381MapG2) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_FP2_TO_G2 precompile logic. // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. // > Output of this call is `256` bytes and is G2 point following respective encoding rules. From 60266f5b05ef2f102eca8b9f9c23cc44d5003268 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 25 Jan 2023 15:05:38 -0500 Subject: [PATCH 27/37] use Prepare on controller --- core/vm/evm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 0b580e47bced..e8814e2ed261 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -44,8 +44,8 @@ type ( // `PrecompileController` allows the EVM to execute a precompiled contract. type PrecompileController interface { - // `SetEphemeralContext` sets the precompile's native environment context. - SetEphemeralContext(ctx context.Context) + // `Prepare` sets the precompile's native environment context and stateDB. + Prepare(ctx context.Context, statedb StateDB) // `Exists` returns if a precompiled contract was found at `addr`. Exists(addr common.Address) (p PrecompiledContract, found bool) From 952aea289a629d57c3d4985135d7da3dbe64d788 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 25 Jan 2023 17:07:28 -0500 Subject: [PATCH 28/37] prepare for state transition --- core/vm/evm.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index e8814e2ed261..7ac8351b6705 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -17,7 +17,6 @@ package vm import ( - "context" "math/big" "sync/atomic" "time" @@ -44,8 +43,9 @@ type ( // `PrecompileController` allows the EVM to execute a precompiled contract. type PrecompileController interface { - // `Prepare` sets the precompile's native environment context and stateDB. - Prepare(ctx context.Context, statedb StateDB) + // `PrepareForStateTransition` holds the precompile native statedb + // before beginning a state transition. + PrepareForStateTransition(statedb StateDB) error // `Exists` returns if a precompiled contract was found at `addr`. Exists(addr common.Address) (p PrecompiledContract, found bool) From ca260e974759bb8d6a618f45d79bedd48b00d959 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Thu, 2 Feb 2023 11:08:39 -0500 Subject: [PATCH 29/37] contract has registry key --- core/vm/contracts.go | 85 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 6c4e91f02dc1..5420d261df38 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -37,6 +37,7 @@ import ( // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { + RegistryKey() common.Address RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) // Run runs the precompiled contract } @@ -144,6 +145,10 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // ECRECOVER implemented as a native contract. type ecrecover struct{} +func (c *ecrecover) RegistryKey() common.Address { + return common.BytesToAddress([]byte{1}) +} + func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } @@ -182,6 +187,10 @@ func (c *ecrecover) Run(ctx context.Context, statedb StateDB, input []byte, call // SHA256 implemented as a native contract. type sha256hash struct{} +func (c *sha256hash) RegistryKey() common.Address { + return common.BytesToAddress([]byte{2}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. // // This method does not require any overflow checking as the input size gas costs @@ -197,6 +206,10 @@ func (c *sha256hash) Run(ctx context.Context, statedb StateDB, input []byte, cal // RIPEMD160 implemented as a native contract. type ripemd160hash struct{} +func (c *ripemd160hash) RegistryKey() common.Address { + return common.BytesToAddress([]byte{3}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. // // This method does not require any overflow checking as the input size gas costs @@ -213,6 +226,10 @@ func (c *ripemd160hash) Run(ctx context.Context, statedb StateDB, input []byte, // data copy implemented as a native contract. type dataCopy struct{} +func (c *dataCopy) RegistryKey() common.Address { + return common.BytesToAddress([]byte{4}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. // // This method does not require any overflow checking as the input size gas costs @@ -229,6 +246,10 @@ type bigModExp struct { eip2565 bool } +func (c *bigModExp) RegistryKey() common.Address { + return common.BytesToAddress([]byte{5}) +} + var ( big0 = big.NewInt(0) big1 = big.NewInt(1) @@ -415,6 +436,10 @@ func runBn256Add(input []byte) ([]byte, error) { // Istanbul consensus rules. type bn256AddIstanbul struct{} +func (c *bn256AddIstanbul) RegistryKey() common.Address { + return common.BytesToAddress([]byte{6}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256AddGasIstanbul @@ -428,6 +453,10 @@ func (c *bn256AddIstanbul) Run(ctx context.Context, statedb StateDB, input []byt // conforming to Byzantium consensus rules. type bn256AddByzantium struct{} +func (c *bn256AddByzantium) RegistryKey() common.Address { + return common.BytesToAddress([]byte{6}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { return params.Bn256AddGasByzantium @@ -453,6 +482,10 @@ func runBn256ScalarMul(input []byte) ([]byte, error) { // multiplication conforming to Istanbul consensus rules. type bn256ScalarMulIstanbul struct{} +func (c *bn256ScalarMulIstanbul) RegistryKey() common.Address { + return common.BytesToAddress([]byte{7}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasIstanbul @@ -466,6 +499,10 @@ func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, statedb StateDB, input // multiplication conforming to Byzantium consensus rules. type bn256ScalarMulByzantium struct{} +func (c *bn256ScalarMulByzantium) RegistryKey() common.Address { + return common.BytesToAddress([]byte{7}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasByzantium @@ -521,6 +558,10 @@ func runBn256Pairing(input []byte) ([]byte, error) { // conforming to Istanbul consensus rules. type bn256PairingIstanbul struct{} +func (c *bn256PairingIstanbul) RegistryKey() common.Address { + return common.BytesToAddress([]byte{8}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul @@ -534,6 +575,10 @@ func (c *bn256PairingIstanbul) Run(ctx context.Context, statedb StateDB, input [ // conforming to Byzantium consensus rules. type bn256PairingByzantium struct{} +func (c *bn256PairingByzantium) RegistryKey() common.Address { + return common.BytesToAddress([]byte{8}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium @@ -545,6 +590,10 @@ func (c *bn256PairingByzantium) Run(ctx context.Context, statedb StateDB, input type blake2F struct{} +func (c *blake2F) RegistryKey() common.Address { + return common.BytesToAddress([]byte{9}) +} + func (c *blake2F) RequiredGas(input []byte) uint64 { // If the input is malformed, we can't calculate the gas, return 0 and let the // actual call choke and fault. @@ -614,6 +663,10 @@ var ( // bls12381G1Add implements EIP-2537 G1Add precompile. type bls12381G1Add struct{} +func (c *bls12381G1Add) RegistryKey() common.Address { + return common.BytesToAddress([]byte{10}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { return params.Bls12381G1AddGas @@ -652,6 +705,10 @@ func (c *bls12381G1Add) Run(ctx context.Context, statedb StateDB, input []byte, // bls12381G1Mul implements EIP-2537 G1Mul precompile. type bls12381G1Mul struct{} +func (c *bls12381G1Mul) RegistryKey() common.Address { + return common.BytesToAddress([]byte{11}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G1MulGas @@ -688,6 +745,10 @@ func (c *bls12381G1Mul) Run(ctx context.Context, statedb StateDB, input []byte, // bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile. type bls12381G1MultiExp struct{} +func (c *bls12381G1MultiExp) RegistryKey() common.Address { + return common.BytesToAddress([]byte{12}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { // Calculate G1 point, scalar value pair length @@ -745,6 +806,10 @@ func (c *bls12381G1MultiExp) Run(ctx context.Context, statedb StateDB, input []b // bls12381G2Add implements EIP-2537 G2Add precompile. type bls12381G2Add struct{} +func (c *bls12381G2Add) RegistryKey() common.Address { + return common.BytesToAddress([]byte{13}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { return params.Bls12381G2AddGas @@ -783,6 +848,10 @@ func (c *bls12381G2Add) Run(ctx context.Context, statedb StateDB, input []byte, // bls12381G2Mul implements EIP-2537 G2Mul precompile. type bls12381G2Mul struct{} +func (c *bls12381G2Mul) RegistryKey() common.Address { + return common.BytesToAddress([]byte{14}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G2MulGas @@ -819,6 +888,10 @@ func (c *bls12381G2Mul) Run(ctx context.Context, statedb StateDB, input []byte, // bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile. type bls12381G2MultiExp struct{} +func (c *bls12381G2MultiExp) RegistryKey() common.Address { + return common.BytesToAddress([]byte{15}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { // Calculate G2 point, scalar value pair length @@ -876,6 +949,10 @@ func (c *bls12381G2MultiExp) Run(ctx context.Context, statedb StateDB, input []b // bls12381Pairing implements EIP-2537 Pairing precompile. type bls12381Pairing struct{} +func (c *bls12381Pairing) RegistryKey() common.Address { + return common.BytesToAddress([]byte{16}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381Pairing) RequiredGas(input []byte) uint64 { return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas @@ -955,6 +1032,10 @@ func decodeBLS12381FieldElement(in []byte) ([]byte, error) { // bls12381MapG1 implements EIP-2537 MapG1 precompile. type bls12381MapG1 struct{} +func (c *bls12381MapG1) RegistryKey() common.Address { + return common.BytesToAddress([]byte{17}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { return params.Bls12381MapG1Gas @@ -990,6 +1071,10 @@ func (c *bls12381MapG1) Run(ctx context.Context, statedb StateDB, input []byte, // bls12381MapG2 implements EIP-2537 MapG2 precompile. type bls12381MapG2 struct{} +func (c *bls12381MapG2) RegistryKey() common.Address { + return common.BytesToAddress([]byte{18}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { return params.Bls12381MapG2Gas From 2ad2464693dd71f004dd567444e0c67279af3d99 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Thu, 2 Feb 2023 12:39:39 -0500 Subject: [PATCH 30/37] has and get --- core/vm/evm.go | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 7ac8351b6705..fcef413cb72c 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -47,8 +47,12 @@ type PrecompileController interface { // before beginning a state transition. PrepareForStateTransition(statedb StateDB) error - // `Exists` returns if a precompiled contract was found at `addr`. - Exists(addr common.Address) (p PrecompiledContract, found bool) + // `Has` returns if a precompiled contract was found at `addr`. + Has(addr common.Address) bool + + // `Get` returns the precompiled contract at `addr`. Returns nil if no + // contract is found at `addr`. + Get(addr common.Address) PrecompiledContract // `Run` runs a precompiled contract and returns the remaining gas. Run(p PrecompiledContract, input []byte, caller common.Address, @@ -185,7 +189,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - p, isPrecompile := evm.PrecompileController.Exists(addr) + isPrecompile := evm.PrecompileController.Has(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -222,7 +226,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.PrecompileController.Run(p, input, caller.Address(), value, gas, false) + ret, gas, err = evm.PrecompileController.Run( + evm.PrecompileController.Get(addr), input, caller.Address(), value, gas, false, + ) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -284,8 +290,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.PrecompileController.Exists(addr); isPrecompile { - ret, gas, err = evm.PrecompileController.Run(p, input, caller.Address(), value, gas, true) + if isPrecompile := evm.PrecompileController.Has(addr); isPrecompile { + ret, gas, err = evm.PrecompileController.Run( + evm.PrecompileController.Get(addr), input, caller.Address(), value, gas, true, + ) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -325,9 +333,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.PrecompileController.Exists(addr); isPrecompile { + if isPrecompile := evm.PrecompileController.Has(addr); isPrecompile { parent := caller.(*Contract) - ret, gas, err = evm.PrecompileController.Run(p, input, parent.CallerAddress, parent.value, gas, false) + ret, gas, err = evm.PrecompileController.Run( + evm.PrecompileController.Get(addr), input, parent.CallerAddress, parent.value, gas, false, + ) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -375,8 +385,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if p, isPrecompile := evm.PrecompileController.Exists(addr); isPrecompile { - ret, gas, err = evm.PrecompileController.Run(p, input, caller.Address(), new(big.Int), gas, true) + if isPrecompile := evm.PrecompileController.Has(addr); isPrecompile { + ret, gas, err = evm.PrecompileController.Run( + evm.PrecompileController.Get(addr), input, caller.Address(), new(big.Int), gas, true, + ) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' From d6fbbb73a2d90e041f3ec37b27f18fb247a58873 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Thu, 2 Feb 2023 12:47:36 -0500 Subject: [PATCH 31/37] controller > manager --- core/vm/evm.go | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index fcef413cb72c..f2219d3db018 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,8 +41,8 @@ type ( GetHashFunc func(uint64) common.Hash ) -// `PrecompileController` allows the EVM to execute a precompiled contract. -type PrecompileController interface { +// `PrecompileManager` allows the EVM to execute a precompiled contract. +type PrecompileManager interface { // `PrepareForStateTransition` holds the precompile native statedb // before beginning a state transition. PrepareForStateTransition(statedb StateDB) error @@ -104,8 +104,8 @@ type EVM struct { TxContext // StateDB gives access to the underlying state StateDB StateDB - // PrecompileController finds and runs precompiled contracts - PrecompileController PrecompileController + // PrecompileManager finds and runs precompiled contracts + PrecompileManager PrecompileManager // Depth is the current call stack depth int @@ -145,10 +145,10 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig func NewEVMWithPrecompiles( blockCtx BlockContext, txCtx TxContext, statedb StateDB, - chainConfig *params.ChainConfig, config Config, precompileController PrecompileController, + chainConfig *params.ChainConfig, config Config, precompileController PrecompileManager, ) *EVM { evm := NewEVM(blockCtx, txCtx, statedb, chainConfig, config) - evm.PrecompileController = precompileController + evm.PrecompileManager = precompileController return evm } @@ -189,7 +189,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - isPrecompile := evm.PrecompileController.Has(addr) + isPrecompile := evm.PrecompileManager.Has(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { @@ -226,8 +226,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.PrecompileController.Run( - evm.PrecompileController.Get(addr), input, caller.Address(), value, gas, false, + ret, gas, err = evm.PrecompileManager.Run( + evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false, ) } else { // Initialise a new contract and set the code that is to be used by the EVM. @@ -290,9 +290,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } // It is allowed to call precompiles, even via delegatecall - if isPrecompile := evm.PrecompileController.Has(addr); isPrecompile { - ret, gas, err = evm.PrecompileController.Run( - evm.PrecompileController.Get(addr), input, caller.Address(), value, gas, true, + if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { + ret, gas, err = evm.PrecompileManager.Run( + evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, true, ) } else { addrCopy := addr @@ -333,10 +333,10 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // It is allowed to call precompiles, even via delegatecall - if isPrecompile := evm.PrecompileController.Has(addr); isPrecompile { + if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { parent := caller.(*Contract) - ret, gas, err = evm.PrecompileController.Run( - evm.PrecompileController.Get(addr), input, parent.CallerAddress, parent.value, gas, false, + ret, gas, err = evm.PrecompileManager.Run( + evm.PrecompileManager.Get(addr), input, parent.CallerAddress, parent.value, gas, false, ) } else { addrCopy := addr @@ -385,9 +385,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte }(gas) } - if isPrecompile := evm.PrecompileController.Has(addr); isPrecompile { - ret, gas, err = evm.PrecompileController.Run( - evm.PrecompileController.Get(addr), input, caller.Address(), new(big.Int), gas, true, + if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { + ret, gas, err = evm.PrecompileManager.Run( + evm.PrecompileManager.Get(addr), input, caller.Address(), new(big.Int), gas, true, ) } else { // At this point, we use a copy of address. If we don't, the go compiler will From e4d555f4ce0cb9cc77034478f7940c61d86e4b39 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Thu, 2 Feb 2023 20:21:37 -0500 Subject: [PATCH 32/37] with statedb --- core/vm/contracts.go | 93 +++++++++++++++++++++++++++++++++----------- core/vm/evm.go | 8 ++-- 2 files changed, 74 insertions(+), 27 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 5420d261df38..bd27b6308a9f 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -37,9 +37,14 @@ import ( // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { + // RegistryKey returns the address at which the contract will be registered. RegistryKey() common.Address - RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use - Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) // Run runs the precompiled contract + // RequiredGas calculates the contract static gas use. + RequiredGas(input []byte) uint64 + // Run runs the precompiled contract with the given context. + Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) + // WithStateDB sets the statedb for the contract to use. + WithStateDB(sdb StateDB) PrecompiledContract } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum @@ -153,7 +158,7 @@ func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *ecrecover) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { const ecRecoverInputLength = 128 input = common.RightPadBytes(input, ecRecoverInputLength) @@ -184,6 +189,8 @@ func (c *ecrecover) Run(ctx context.Context, statedb StateDB, input []byte, call return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil } +func (c *ecrecover) WithStateDB(StateDB) PrecompiledContract { return c } + // SHA256 implemented as a native contract. type sha256hash struct{} @@ -198,11 +205,13 @@ func (c *sha256hash) RegistryKey() common.Address { func (c *sha256hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas } -func (c *sha256hash) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *sha256hash) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { h := sha256.Sum256(input) return h[:], nil } +func (c *sha256hash) WithStateDB(StateDB) PrecompiledContract { return c } + // RIPEMD160 implemented as a native contract. type ripemd160hash struct{} @@ -217,12 +226,14 @@ func (c *ripemd160hash) RegistryKey() common.Address { func (c *ripemd160hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas } -func (c *ripemd160hash) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *ripemd160hash) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil } +func (c *ripemd160hash) WithStateDB(StateDB) PrecompiledContract { return c } + // data copy implemented as a native contract. type dataCopy struct{} @@ -237,10 +248,12 @@ func (c *dataCopy) RegistryKey() common.Address { func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } -func (c *dataCopy) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *dataCopy) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return input, nil } +func (c *dataCopy) WithStateDB(StateDB) PrecompiledContract { return c } + // bigModExp implements a native big integer exponential modular operation. type bigModExp struct { eip2565 bool @@ -368,7 +381,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { return gas.Uint64() } -func (c *bigModExp) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bigModExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { var ( baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() @@ -396,6 +409,8 @@ func (c *bigModExp) Run(ctx context.Context, statedb StateDB, input []byte, call return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil } +func (c *bigModExp) WithStateDB(StateDB) PrecompiledContract { return c } + // newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point, // returning it, or an error if the point is invalid. func newCurvePoint(blob []byte) (*bn256.G1, error) { @@ -445,10 +460,12 @@ func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256AddGasIstanbul } -func (c *bn256AddIstanbul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256AddIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Add(input) } +func (c *bn256AddIstanbul) WithStateDB(StateDB) PrecompiledContract { return c } + // bn256AddByzantium implements a native elliptic curve point addition // conforming to Byzantium consensus rules. type bn256AddByzantium struct{} @@ -462,10 +479,12 @@ func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { return params.Bn256AddGasByzantium } -func (c *bn256AddByzantium) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256AddByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Add(input) } +func (c *bn256AddByzantium) WithStateDB(StateDB) PrecompiledContract { return c } + // runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by // both Byzantium and Istanbul operations. func runBn256ScalarMul(input []byte) ([]byte, error) { @@ -491,10 +510,12 @@ func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasIstanbul } -func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256ScalarMul(input) } +func (c *bn256ScalarMulIstanbul) WithStateDB(StateDB) PrecompiledContract { return c } + // bn256ScalarMulByzantium implements a native elliptic curve scalar // multiplication conforming to Byzantium consensus rules. type bn256ScalarMulByzantium struct{} @@ -508,10 +529,12 @@ func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasByzantium } -func (c *bn256ScalarMulByzantium) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256ScalarMulByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256ScalarMul(input) } +func (c *bn256ScalarMulByzantium) WithStateDB(StateDB) PrecompiledContract { return c } + var ( // true32Byte is returned if the bn256 pairing check succeeds. true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} @@ -567,10 +590,12 @@ func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul } -func (c *bn256PairingIstanbul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256PairingIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Pairing(input) } +func (c *bn256PairingIstanbul) WithStateDB(StateDB) PrecompiledContract { return c } + // bn256PairingByzantium implements a pairing pre-compile for the bn256 curve // conforming to Byzantium consensus rules. type bn256PairingByzantium struct{} @@ -584,10 +609,12 @@ func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium } -func (c *bn256PairingByzantium) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bn256PairingByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { return runBn256Pairing(input) } +func (c *bn256PairingByzantium) WithStateDB(StateDB) PrecompiledContract { return c } + type blake2F struct{} func (c *blake2F) RegistryKey() common.Address { @@ -614,7 +641,7 @@ var ( errBlake2FInvalidFinalFlag = errors.New("invalid final flag") ) -func (c *blake2F) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *blake2F) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Make sure the input is valid (correct length and final flag) if len(input) != blake2FInputLength { return nil, errBlake2FInvalidInputLength @@ -653,6 +680,8 @@ func (c *blake2F) Run(ctx context.Context, statedb StateDB, input []byte, caller return output, nil } +func (c *blake2F) WithStateDB(StateDB) PrecompiledContract { return c } + var ( errBLS12381InvalidInputLength = errors.New("invalid input length") errBLS12381InvalidFieldElementTopBytes = errors.New("invalid field element top bytes") @@ -672,7 +701,7 @@ func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { return params.Bls12381G1AddGas } -func (c *bls12381G1Add) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1Add) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1Add precompile. // > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each). // > Output is an encoding of addition operation result - single G1 point (`128` bytes). @@ -702,6 +731,8 @@ func (c *bls12381G1Add) Run(ctx context.Context, statedb StateDB, input []byte, return g.EncodePoint(r), nil } +func (c *bls12381G1Add) WithStateDB(StateDB) PrecompiledContract { return c } + // bls12381G1Mul implements EIP-2537 G1Mul precompile. type bls12381G1Mul struct{} @@ -714,7 +745,7 @@ func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G1MulGas } -func (c *bls12381G1Mul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1Mul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1Mul precompile. // > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G1 point (`128` bytes). @@ -742,6 +773,8 @@ func (c *bls12381G1Mul) Run(ctx context.Context, statedb StateDB, input []byte, return g.EncodePoint(r), nil } +func (c *bls12381G1Mul) WithStateDB(StateDB) PrecompiledContract { return c } + // bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile. type bls12381G1MultiExp struct{} @@ -768,7 +801,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000 } -func (c *bls12381G1MultiExp) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G1MultiExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G1MultiExp precompile. // G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes). @@ -803,6 +836,8 @@ func (c *bls12381G1MultiExp) Run(ctx context.Context, statedb StateDB, input []b return g.EncodePoint(r), nil } +func (c *bls12381G1MultiExp) WithStateDB(StateDB) PrecompiledContract { return c } + // bls12381G2Add implements EIP-2537 G2Add precompile. type bls12381G2Add struct{} @@ -815,7 +850,7 @@ func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { return params.Bls12381G2AddGas } -func (c *bls12381G2Add) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2Add) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2Add precompile. // > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each). // > Output is an encoding of addition operation result - single G2 point (`256` bytes). @@ -845,6 +880,8 @@ func (c *bls12381G2Add) Run(ctx context.Context, statedb StateDB, input []byte, return g.EncodePoint(r), nil } +func (c *bls12381G2Add) WithStateDB(StateDB) PrecompiledContract { return c } + // bls12381G2Mul implements EIP-2537 G2Mul precompile. type bls12381G2Mul struct{} @@ -857,7 +894,7 @@ func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G2MulGas } -func (c *bls12381G2Mul) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2Mul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2MUL precompile logic. // > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G2 point (`256` bytes). @@ -885,6 +922,8 @@ func (c *bls12381G2Mul) Run(ctx context.Context, statedb StateDB, input []byte, return g.EncodePoint(r), nil } +func (c *bls12381G2Mul) WithStateDB(StateDB) PrecompiledContract { return c } + // bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile. type bls12381G2MultiExp struct{} @@ -911,7 +950,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000 } -func (c *bls12381G2MultiExp) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381G2MultiExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 G2MultiExp precompile logic // > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes). @@ -946,6 +985,8 @@ func (c *bls12381G2MultiExp) Run(ctx context.Context, statedb StateDB, input []b return g.EncodePoint(r), nil } +func (c *bls12381G2MultiExp) WithStateDB(StateDB) PrecompiledContract { return c } + // bls12381Pairing implements EIP-2537 Pairing precompile. type bls12381Pairing struct{} @@ -958,7 +999,7 @@ func (c *bls12381Pairing) RequiredGas(input []byte) uint64 { return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas } -func (c *bls12381Pairing) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381Pairing) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Pairing precompile logic. // > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure: // > - `128` bytes of G1 point encoding @@ -1012,6 +1053,8 @@ func (c *bls12381Pairing) Run(ctx context.Context, statedb StateDB, input []byte return out, nil } +func (c *bls12381Pairing) WithStateDB(StateDB) PrecompiledContract { return c } + // decodeBLS12381FieldElement decodes BLS12-381 elliptic curve field element. // Removes top 16 bytes of 64 byte input. func decodeBLS12381FieldElement(in []byte) ([]byte, error) { @@ -1041,7 +1084,7 @@ func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { return params.Bls12381MapG1Gas } -func (c *bls12381MapG1) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381MapG1) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_To_G1 precompile. // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. // > Output of this call is `128` bytes and is G1 point following respective encoding rules. @@ -1068,6 +1111,8 @@ func (c *bls12381MapG1) Run(ctx context.Context, statedb StateDB, input []byte, return g.EncodePoint(r), nil } +func (c *bls12381MapG1) WithStateDB(StateDB) PrecompiledContract { return c } + // bls12381MapG2 implements EIP-2537 MapG2 precompile. type bls12381MapG2 struct{} @@ -1080,7 +1125,7 @@ func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { return params.Bls12381MapG2Gas } -func (c *bls12381MapG2) Run(ctx context.Context, statedb StateDB, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { +func (c *bls12381MapG2) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_FP2_TO_G2 precompile logic. // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. // > Output of this call is `256` bytes and is G2 point following respective encoding rules. @@ -1113,3 +1158,5 @@ func (c *bls12381MapG2) Run(ctx context.Context, statedb StateDB, input []byte, // Encode the G2 point to 256 bytes return g.EncodePoint(r), nil } + +func (c *bls12381MapG2) WithStateDB(StateDB) PrecompiledContract { return c } diff --git a/core/vm/evm.go b/core/vm/evm.go index f2219d3db018..6d3d400df8e2 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -227,7 +227,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if isPrecompile { ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false, + evm.PrecompileManager.Get(addr).WithStateDB(evm.StateDB), input, caller.Address(), value, gas, false, ) } else { // Initialise a new contract and set the code that is to be used by the EVM. @@ -292,7 +292,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // It is allowed to call precompiles, even via delegatecall if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, true, + evm.PrecompileManager.Get(addr).WithStateDB(evm.StateDB), input, caller.Address(), value, gas, true, ) } else { addrCopy := addr @@ -336,7 +336,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { parent := caller.(*Contract) ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr), input, parent.CallerAddress, parent.value, gas, false, + evm.PrecompileManager.Get(addr).WithStateDB(evm.StateDB), input, parent.CallerAddress, parent.value, gas, false, ) } else { addrCopy := addr @@ -387,7 +387,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr), input, caller.Address(), new(big.Int), gas, true, + evm.PrecompileManager.Get(addr).WithStateDB(evm.StateDB), input, caller.Address(), new(big.Int), gas, true, ) } else { // At this point, we use a copy of address. If we don't, the go compiler will From fe0db7703f9312aa2f0661135a995af871f3d954 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Thu, 2 Feb 2023 20:34:16 -0500 Subject: [PATCH 33/37] with ctx --- core/vm/evm.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 6d3d400df8e2..ffeb3bae9810 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -17,6 +17,7 @@ package vm import ( + "context" "math/big" "sync/atomic" "time" @@ -43,9 +44,9 @@ type ( // `PrecompileManager` allows the EVM to execute a precompiled contract. type PrecompileManager interface { - // `PrepareForStateTransition` holds the precompile native statedb + // `PrepareForStateTransition` sets the native precompile context // before beginning a state transition. - PrepareForStateTransition(statedb StateDB) error + PrepareForStateTransition(ctx context.Context) error // `Has` returns if a precompiled contract was found at `addr`. Has(addr common.Address) bool From 0d5324b7a63011afa0b522df636e6237f2dd6bf3 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Mon, 6 Feb 2023 18:19:37 -0500 Subject: [PATCH 34/37] simple precompile manager --- core/vm/contracts.go | 44 -------------------------------------------- core/vm/evm.go | 15 ++++++++------- 2 files changed, 8 insertions(+), 51 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index bd27b6308a9f..3f7c92d9514e 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -43,8 +43,6 @@ type PrecompiledContract interface { RequiredGas(input []byte) uint64 // Run runs the precompiled contract with the given context. Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) - // WithStateDB sets the statedb for the contract to use. - WithStateDB(sdb StateDB) PrecompiledContract } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum @@ -189,8 +187,6 @@ func (c *ecrecover) Run(ctx context.Context, input []byte, caller common.Address return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil } -func (c *ecrecover) WithStateDB(StateDB) PrecompiledContract { return c } - // SHA256 implemented as a native contract. type sha256hash struct{} @@ -210,8 +206,6 @@ func (c *sha256hash) Run(ctx context.Context, input []byte, caller common.Addres return h[:], nil } -func (c *sha256hash) WithStateDB(StateDB) PrecompiledContract { return c } - // RIPEMD160 implemented as a native contract. type ripemd160hash struct{} @@ -232,8 +226,6 @@ func (c *ripemd160hash) Run(ctx context.Context, input []byte, caller common.Add return common.LeftPadBytes(ripemd.Sum(nil), 32), nil } -func (c *ripemd160hash) WithStateDB(StateDB) PrecompiledContract { return c } - // data copy implemented as a native contract. type dataCopy struct{} @@ -252,8 +244,6 @@ func (c *dataCopy) Run(ctx context.Context, input []byte, caller common.Address, return input, nil } -func (c *dataCopy) WithStateDB(StateDB) PrecompiledContract { return c } - // bigModExp implements a native big integer exponential modular operation. type bigModExp struct { eip2565 bool @@ -409,8 +399,6 @@ func (c *bigModExp) Run(ctx context.Context, input []byte, caller common.Address return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil } -func (c *bigModExp) WithStateDB(StateDB) PrecompiledContract { return c } - // newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point, // returning it, or an error if the point is invalid. func newCurvePoint(blob []byte) (*bn256.G1, error) { @@ -464,8 +452,6 @@ func (c *bn256AddIstanbul) Run(ctx context.Context, input []byte, caller common. return runBn256Add(input) } -func (c *bn256AddIstanbul) WithStateDB(StateDB) PrecompiledContract { return c } - // bn256AddByzantium implements a native elliptic curve point addition // conforming to Byzantium consensus rules. type bn256AddByzantium struct{} @@ -483,8 +469,6 @@ func (c *bn256AddByzantium) Run(ctx context.Context, input []byte, caller common return runBn256Add(input) } -func (c *bn256AddByzantium) WithStateDB(StateDB) PrecompiledContract { return c } - // runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by // both Byzantium and Istanbul operations. func runBn256ScalarMul(input []byte) ([]byte, error) { @@ -514,8 +498,6 @@ func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, input []byte, caller c return runBn256ScalarMul(input) } -func (c *bn256ScalarMulIstanbul) WithStateDB(StateDB) PrecompiledContract { return c } - // bn256ScalarMulByzantium implements a native elliptic curve scalar // multiplication conforming to Byzantium consensus rules. type bn256ScalarMulByzantium struct{} @@ -533,8 +515,6 @@ func (c *bn256ScalarMulByzantium) Run(ctx context.Context, input []byte, caller return runBn256ScalarMul(input) } -func (c *bn256ScalarMulByzantium) WithStateDB(StateDB) PrecompiledContract { return c } - var ( // true32Byte is returned if the bn256 pairing check succeeds. true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} @@ -594,8 +574,6 @@ func (c *bn256PairingIstanbul) Run(ctx context.Context, input []byte, caller com return runBn256Pairing(input) } -func (c *bn256PairingIstanbul) WithStateDB(StateDB) PrecompiledContract { return c } - // bn256PairingByzantium implements a pairing pre-compile for the bn256 curve // conforming to Byzantium consensus rules. type bn256PairingByzantium struct{} @@ -613,8 +591,6 @@ func (c *bn256PairingByzantium) Run(ctx context.Context, input []byte, caller co return runBn256Pairing(input) } -func (c *bn256PairingByzantium) WithStateDB(StateDB) PrecompiledContract { return c } - type blake2F struct{} func (c *blake2F) RegistryKey() common.Address { @@ -680,8 +656,6 @@ func (c *blake2F) Run(ctx context.Context, input []byte, caller common.Address, return output, nil } -func (c *blake2F) WithStateDB(StateDB) PrecompiledContract { return c } - var ( errBLS12381InvalidInputLength = errors.New("invalid input length") errBLS12381InvalidFieldElementTopBytes = errors.New("invalid field element top bytes") @@ -731,8 +705,6 @@ func (c *bls12381G1Add) Run(ctx context.Context, input []byte, caller common.Add return g.EncodePoint(r), nil } -func (c *bls12381G1Add) WithStateDB(StateDB) PrecompiledContract { return c } - // bls12381G1Mul implements EIP-2537 G1Mul precompile. type bls12381G1Mul struct{} @@ -773,8 +745,6 @@ func (c *bls12381G1Mul) Run(ctx context.Context, input []byte, caller common.Add return g.EncodePoint(r), nil } -func (c *bls12381G1Mul) WithStateDB(StateDB) PrecompiledContract { return c } - // bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile. type bls12381G1MultiExp struct{} @@ -836,8 +806,6 @@ func (c *bls12381G1MultiExp) Run(ctx context.Context, input []byte, caller commo return g.EncodePoint(r), nil } -func (c *bls12381G1MultiExp) WithStateDB(StateDB) PrecompiledContract { return c } - // bls12381G2Add implements EIP-2537 G2Add precompile. type bls12381G2Add struct{} @@ -880,8 +848,6 @@ func (c *bls12381G2Add) Run(ctx context.Context, input []byte, caller common.Add return g.EncodePoint(r), nil } -func (c *bls12381G2Add) WithStateDB(StateDB) PrecompiledContract { return c } - // bls12381G2Mul implements EIP-2537 G2Mul precompile. type bls12381G2Mul struct{} @@ -922,8 +888,6 @@ func (c *bls12381G2Mul) Run(ctx context.Context, input []byte, caller common.Add return g.EncodePoint(r), nil } -func (c *bls12381G2Mul) WithStateDB(StateDB) PrecompiledContract { return c } - // bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile. type bls12381G2MultiExp struct{} @@ -985,8 +949,6 @@ func (c *bls12381G2MultiExp) Run(ctx context.Context, input []byte, caller commo return g.EncodePoint(r), nil } -func (c *bls12381G2MultiExp) WithStateDB(StateDB) PrecompiledContract { return c } - // bls12381Pairing implements EIP-2537 Pairing precompile. type bls12381Pairing struct{} @@ -1053,8 +1015,6 @@ func (c *bls12381Pairing) Run(ctx context.Context, input []byte, caller common.A return out, nil } -func (c *bls12381Pairing) WithStateDB(StateDB) PrecompiledContract { return c } - // decodeBLS12381FieldElement decodes BLS12-381 elliptic curve field element. // Removes top 16 bytes of 64 byte input. func decodeBLS12381FieldElement(in []byte) ([]byte, error) { @@ -1111,8 +1071,6 @@ func (c *bls12381MapG1) Run(ctx context.Context, input []byte, caller common.Add return g.EncodePoint(r), nil } -func (c *bls12381MapG1) WithStateDB(StateDB) PrecompiledContract { return c } - // bls12381MapG2 implements EIP-2537 MapG2 precompile. type bls12381MapG2 struct{} @@ -1158,5 +1116,3 @@ func (c *bls12381MapG2) Run(ctx context.Context, input []byte, caller common.Add // Encode the G2 point to 256 bytes return g.EncodePoint(r), nil } - -func (c *bls12381MapG2) WithStateDB(StateDB) PrecompiledContract { return c } diff --git a/core/vm/evm.go b/core/vm/evm.go index ffeb3bae9810..3a2e5abeca78 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -44,9 +44,9 @@ type ( // `PrecompileManager` allows the EVM to execute a precompiled contract. type PrecompileManager interface { - // `PrepareForStateTransition` sets the native precompile context - // before beginning a state transition. - PrepareForStateTransition(ctx context.Context) error + // `Reset` sets the native precompile context before beginning a state + // transition. + Reset(ctx context.Context) // `Has` returns if a precompiled contract was found at `addr`. Has(addr common.Address) bool @@ -227,8 +227,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { + ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr).WithStateDB(evm.StateDB), input, caller.Address(), value, gas, false, + evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false, ) } else { // Initialise a new contract and set the code that is to be used by the EVM. @@ -293,7 +294,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // It is allowed to call precompiles, even via delegatecall if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr).WithStateDB(evm.StateDB), input, caller.Address(), value, gas, true, + evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, true, ) } else { addrCopy := addr @@ -337,7 +338,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { parent := caller.(*Contract) ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr).WithStateDB(evm.StateDB), input, parent.CallerAddress, parent.value, gas, false, + evm.PrecompileManager.Get(addr), input, parent.CallerAddress, parent.value, gas, false, ) } else { addrCopy := addr @@ -388,7 +389,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr).WithStateDB(evm.StateDB), input, caller.Address(), new(big.Int), gas, true, + evm.PrecompileManager.Get(addr), input, caller.Address(), new(big.Int), gas, true, ) } else { // At this point, we use a copy of address. If we don't, the go compiler will From 561d4bc00bc4cd3c02ed8579d2bcaa0fb9168980 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Fri, 10 Feb 2023 11:16:16 -0500 Subject: [PATCH 35/37] allow setting block context to evm --- core/vm/contracts_test.go | 12 ++++++++++++ core/vm/evm.go | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index b22d999e6cd9..4ed94d93a950 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -18,8 +18,10 @@ package vm import ( "bytes" + "context" "encoding/json" "fmt" + "math/big" "os" "testing" "time" @@ -91,6 +93,16 @@ var blake2FMalformedInputTests = []precompiledFailureTest{ }, } +func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { + gasCost := p.RequiredGas(input) + if suppliedGas < gasCost { + return nil, 0, ErrOutOfGas + } + suppliedGas -= gasCost + output, err := p.Run(context.Background(), input, common.Address{}, new(big.Int), true) + return output, suppliedGas, err +} + func testPrecompiled(addr string, test precompiledTest, t *testing.T) { p := allPrecompiles[common.HexToAddress(addr)] in := common.Hex2Bytes(test.Input) diff --git a/core/vm/evm.go b/core/vm/evm.go index 3a2e5abeca78..f2dd8ff78bf3 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -176,6 +176,13 @@ func (evm *EVM) Interpreter() *EVMInterpreter { return evm.interpreter } +// SetBlockContext updates the block context of the EVM. +func (evm *EVM) SetBlockContext(blockCtx BlockContext) { + evm.Context = blockCtx + num := blockCtx.BlockNumber + evm.chainRules = evm.chainConfig.Rules(num, blockCtx.Random != nil) +} + // Call executes the contract associated with the addr with the given input as // parameters. It also handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an From 62f77548da9a285c1b1ff0c71f0c24eaa1bb4cf5 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Fri, 10 Feb 2023 12:34:29 -0500 Subject: [PATCH 36/37] remove unneded evm funcs --- core/vm/evm.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index f2dd8ff78bf3..3a2e5abeca78 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -176,13 +176,6 @@ func (evm *EVM) Interpreter() *EVMInterpreter { return evm.interpreter } -// SetBlockContext updates the block context of the EVM. -func (evm *EVM) SetBlockContext(blockCtx BlockContext) { - evm.Context = blockCtx - num := blockCtx.BlockNumber - evm.chainRules = evm.chainConfig.Rules(num, blockCtx.Random != nil) -} - // Call executes the contract associated with the addr with the given input as // parameters. It also handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an From 6096143235f047b0946d5d0d95eba7145c1aa516 Mon Sep 17 00:00:00 2001 From: Cal Bera Date: Wed, 15 Feb 2023 19:28:51 -0500 Subject: [PATCH 37/37] simplify precompile manager --- core/vm/evm.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 3a2e5abeca78..838dc199e7f6 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -44,8 +44,6 @@ type ( // `PrecompileManager` allows the EVM to execute a precompiled contract. type PrecompileManager interface { - // `Reset` sets the native precompile context before beginning a state - // transition. Reset(ctx context.Context) // `Has` returns if a precompiled contract was found at `addr`. @@ -56,7 +54,7 @@ type PrecompileManager interface { Get(addr common.Address) PrecompiledContract // `Run` runs a precompiled contract and returns the remaining gas. - Run(p PrecompiledContract, input []byte, caller common.Address, + Run(sdb StateDB, p PrecompiledContract, input []byte, caller common.Address, value *big.Int, suppliedGas uint64, readonly bool, ) (ret []byte, remainingGas uint64, err error) } @@ -227,9 +225,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false, + evm.StateDB, evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false, ) } else { // Initialise a new contract and set the code that is to be used by the EVM. @@ -294,7 +291,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // It is allowed to call precompiles, even via delegatecall if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, true, + evm.StateDB, evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, true, ) } else { addrCopy := addr @@ -338,7 +335,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { parent := caller.(*Contract) ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr), input, parent.CallerAddress, parent.value, gas, false, + evm.StateDB, evm.PrecompileManager.Get(addr), input, parent.CallerAddress, parent.value, gas, false, ) } else { addrCopy := addr @@ -389,7 +386,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile { ret, gas, err = evm.PrecompileManager.Run( - evm.PrecompileManager.Get(addr), input, caller.Address(), new(big.Int), gas, true, + evm.StateDB, evm.PrecompileManager.Get(addr), input, caller.Address(), new(big.Int), gas, true, ) } else { // At this point, we use a copy of address. If we don't, the go compiler will