diff --git a/.github/matic-cli-config.yml b/.github/matic-cli-config.yml index 2b83b684c6..8bdfe82b3b 100644 --- a/.github/matic-cli-config.yml +++ b/.github/matic-cli-config.yml @@ -3,9 +3,13 @@ defaultFee: 2000 borChainId: "15001" heimdallChainId: heimdall-15001 contractsBranch: jc/v0.3.1-backport +sprintSize: 64 +blockNumber: '0' +blockTime: '2' numOfValidators: 3 numOfNonValidators: 0 ethURL: http://ganache:9545 +ethHostUser: ubuntu devnetType: docker borDockerBuildContext: "../../bor" heimdallDockerBuildContext: "https://github.com/maticnetwork/heimdall.git#develop" diff --git a/builder/files/config.toml b/builder/files/config.toml index 0d01f85d71..870c164a8d 100644 --- a/builder/files/config.toml +++ b/builder/files/config.toml @@ -78,8 +78,7 @@ syncmode = "full" # prefix = "" # host = "localhost" # api = ["web3", "net"] - # vhosts = ["*"] - # corsdomain = ["*"] + # origins = ["*"] # [jsonrpc.graphql] # enabled = false # port = 0 @@ -122,6 +121,7 @@ syncmode = "full" # noprefetch = false # preimages = false # txlookuplimit = 2350000 + # triesinmemory = 128 [accounts] # allow-insecure-unlock = true diff --git a/cmd/geth/config.go b/cmd/geth/config.go index e6cb36b121..80bf95b1ac 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -327,7 +327,7 @@ func setDefaultMumbaiGethConfig(ctx *cli.Context, config *gethConfig) { config.Eth.TxPool.AccountQueue = 64 config.Eth.TxPool.GlobalQueue = 131072 config.Eth.TxPool.Lifetime = 90 * time.Minute - config.Node.P2P.MaxPeers = 200 + config.Node.P2P.MaxPeers = 50 config.Metrics.Enabled = true // --pprof is enabled in 'internal/debug/flags.go' } @@ -350,7 +350,7 @@ func setDefaultBorMainnetGethConfig(ctx *cli.Context, config *gethConfig) { config.Eth.TxPool.AccountQueue = 64 config.Eth.TxPool.GlobalQueue = 131072 config.Eth.TxPool.Lifetime = 90 * time.Minute - config.Node.P2P.MaxPeers = 200 + config.Node.P2P.MaxPeers = 50 config.Metrics.Enabled = true // --pprof is enabled in 'internal/debug/flags.go' } diff --git a/consensus/bor/snapshot_test.go b/consensus/bor/snapshot_test.go index 503bd18b24..68a9ba042f 100644 --- a/consensus/bor/snapshot_test.go +++ b/consensus/bor/snapshot_test.go @@ -5,7 +5,7 @@ import ( "sort" "testing" - "github.com/JekaMas/crand" + "github.com/maticnetwork/crand" "github.com/stretchr/testify/require" "pgregory.net/rapid" diff --git a/consensus/bor/statefull/processor.go b/consensus/bor/statefull/processor.go index c87d4f4ff4..0fe9baeeba 100644 --- a/consensus/bor/statefull/processor.go +++ b/consensus/bor/statefull/processor.go @@ -31,22 +31,22 @@ func (c ChainContext) GetHeader(hash common.Hash, number uint64) *types.Header { } // callmsg implements core.Message to allow passing it as a transaction simulator. -type callmsg struct { +type Callmsg struct { ethereum.CallMsg } -func (m callmsg) From() common.Address { return m.CallMsg.From } -func (m callmsg) Nonce() uint64 { return 0 } -func (m callmsg) CheckNonce() bool { return false } -func (m callmsg) To() *common.Address { return m.CallMsg.To } -func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } -func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } -func (m callmsg) Value() *big.Int { return m.CallMsg.Value } -func (m callmsg) Data() []byte { return m.CallMsg.Data } +func (m Callmsg) From() common.Address { return m.CallMsg.From } +func (m Callmsg) Nonce() uint64 { return 0 } +func (m Callmsg) CheckNonce() bool { return false } +func (m Callmsg) To() *common.Address { return m.CallMsg.To } +func (m Callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } +func (m Callmsg) Gas() uint64 { return m.CallMsg.Gas } +func (m Callmsg) Value() *big.Int { return m.CallMsg.Value } +func (m Callmsg) Data() []byte { return m.CallMsg.Data } // get system message -func GetSystemMessage(toAddress common.Address, data []byte) callmsg { - return callmsg{ +func GetSystemMessage(toAddress common.Address, data []byte) Callmsg { + return Callmsg{ ethereum.CallMsg{ From: systemAddress, Gas: math.MaxUint64 / 2, @@ -61,7 +61,7 @@ func GetSystemMessage(toAddress common.Address, data []byte) callmsg { // apply message func ApplyMessage( _ context.Context, - msg callmsg, + msg Callmsg, state *state.StateDB, header *types.Header, chainConfig *params.ChainConfig, @@ -93,3 +93,28 @@ func ApplyMessage( return gasUsed, nil } + +func ApplyBorMessage(vmenv vm.EVM, msg Callmsg) (*core.ExecutionResult, error) { + initialGas := msg.Gas() + + // Apply the transaction to the current state (included in the env) + ret, gasLeft, err := vmenv.Call( + vm.AccountRef(msg.From()), + *msg.To(), + msg.Data(), + msg.Gas(), + msg.Value(), + ) + // Update the state with pending changes + if err != nil { + vmenv.StateDB.Finalise(true) + } + + gasUsed := initialGas - gasLeft + + return &core.ExecutionResult{ + UsedGas: gasUsed, + Err: err, + ReturnData: ret, + }, nil +} diff --git a/core/blockchain.go b/core/blockchain.go index 48d5e966db..8103e4a05e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -92,7 +92,6 @@ const ( txLookupCacheLimit = 1024 maxFutureBlocks = 256 maxTimeFutureBlocks = 30 - TriesInMemory = 128 // BlockChainVersion ensures that an incompatible database forces a resync from scratch. // @@ -132,6 +131,7 @@ type CacheConfig struct { TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory Preimages bool // Whether to store preimage of trie key to the disk + TriesInMemory uint64 // Number of recent tries to keep in memory SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } @@ -144,6 +144,7 @@ var DefaultCacheConfig = &CacheConfig{ TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, SnapshotWait: true, + TriesInMemory: 128, } // BlockChain represents the canonical chain given a database with a genesis @@ -229,6 +230,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par if cacheConfig == nil { cacheConfig = DefaultCacheConfig } + + if cacheConfig.TriesInMemory <= 0 { + cacheConfig.TriesInMemory = DefaultCacheConfig.TriesInMemory + } bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) receiptsCache, _ := lru.New(receiptsCacheLimit) @@ -829,7 +834,7 @@ func (bc *BlockChain) Stop() { if !bc.cacheConfig.TrieDirtyDisabled { triedb := bc.stateCache.TrieDB() - for _, offset := range []uint64{0, 1, TriesInMemory - 1} { + for _, offset := range []uint64{0, 1, bc.cacheConfig.TriesInMemory - 1} { if number := bc.CurrentBlock().NumberU64(); number > offset { recent := bc.GetBlockByNumber(number - offset) @@ -1297,7 +1302,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive bc.triegc.Push(root, -int64(block.NumberU64())) - if current := block.NumberU64(); current > TriesInMemory { + if current := block.NumberU64(); current > bc.cacheConfig.TriesInMemory { // If we exceeded our memory allowance, flush matured singleton nodes to disk var ( nodes, imgs = triedb.Size() @@ -1307,7 +1312,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. triedb.Cap(limit - ethdb.IdealBatchSize) } // Find the next state trie we need to commit - chosen := current - TriesInMemory + chosen := current - bc.cacheConfig.TriesInMemory // If we exceeded out time allowance, flush an entire trie to disk if bc.gcproc > bc.cacheConfig.TrieTimeLimit { @@ -1319,8 +1324,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } else { // If we're exceeding limits but haven't reached a large enough memory gap, // warn the user that the system is becoming unstable. - if chosen < lastWrite+TriesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { - log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/TriesInMemory) + if chosen < lastWrite+bc.cacheConfig.TriesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { + log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TriesInMemory, "optimum", float64(chosen-lastWrite)/float64((bc.cacheConfig.TriesInMemory))) } // Flush an entire trie and restart the counters triedb.Commit(header.Root, true, nil) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index b2c14f81ba..fa6b61225e 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1652,7 +1652,7 @@ func TestTrieForkGC(t *testing.T) { db := rawdb.NewMemoryDatabase() genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain forks := make([]*types.Block, len(blocks)) @@ -1681,7 +1681,7 @@ func TestTrieForkGC(t *testing.T) { } } // Dereference all the recent tries and ensure no past trie is left in - for i := 0; i < TriesInMemory; i++ { + for i := 0; i < int(chain.cacheConfig.TriesInMemory); i++ { chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) } @@ -1700,8 +1700,8 @@ func TestLargeReorgTrieGC(t *testing.T) { genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) - competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) + original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*int(DefaultCacheConfig.TriesInMemory)+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one diskdb := rawdb.NewMemoryDatabase() @@ -1736,7 +1736,8 @@ func TestLargeReorgTrieGC(t *testing.T) { if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { t.Fatalf("failed to finalize competitor chain: %v", err) } - for i, block := range competitor[:len(competitor)-TriesInMemory] { + + for i, block := range competitor[:len(competitor)-int(chain.cacheConfig.TriesInMemory)] { if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { t.Fatalf("competitor %d: competing chain state missing", i) } @@ -1882,8 +1883,8 @@ func TestInsertReceiptChainRollback(t *testing.T) { // overtake the 'canon' chain until after it's passed canon by about 200 blocks. // // Details at: -// - https://github.com/ethereum/go-ethereum/issues/18977 -// - https://github.com/ethereum/go-ethereum/pull/18988 +// - https://github.com/ethereum/go-ethereum/issues/18977 +// - https://github.com/ethereum/go-ethereum/pull/18988 func TestLowDiffLongChain(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() @@ -1892,7 +1893,7 @@ func TestLowDiffLongChain(t *testing.T) { // We must use a pretty long chain to ensure that the fork doesn't overtake us // until after at least 128 blocks post tip - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*TriesInMemory, func(i int, b *BlockGen) { + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) }) @@ -1910,7 +1911,7 @@ func TestLowDiffLongChain(t *testing.T) { } // Generate fork chain, starting from an early block parent := blocks[10] - fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) @@ -1979,7 +1980,8 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Set the terminal total difficulty in the config gspec.Config.TerminalTotalDifficulty = big.NewInt(0) } - blocks, _ := GenerateChain(&chainConfig, genesis, genEngine, db, 2*TriesInMemory, func(i int, gen *BlockGen) { + + blocks, _ := GenerateChain(&chainConfig, genesis, genEngine, db, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key) if err != nil { t.Fatalf("failed to create tx: %v", err) @@ -1991,9 +1993,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - lastPrunedIndex := len(blocks) - TriesInMemory - 1 + lastPrunedIndex := len(blocks) - int(chain.cacheConfig.TriesInMemory) - 1 lastPrunedBlock := blocks[lastPrunedIndex] - firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] + firstNonPrunedBlock := blocks[len(blocks)-int(chain.cacheConfig.TriesInMemory)] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { @@ -2019,7 +2021,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate fork chain, make it longer than canon parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock parent := blocks[parentIndex] - fork, _ := GenerateChain(&chainConfig, parent, genEngine, db, 2*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(&chainConfig, parent, genEngine, db, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) // Prepend the parent(s) @@ -2046,7 +2048,8 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // That is: the sidechain for import contains some blocks already present in canon chain. // So the blocks are // [ Cn, Cn+1, Cc, Sn+3 ... Sm] -// ^ ^ ^ pruned +// +// ^ ^ ^ pruned func TestPrunedImportSide(t *testing.T) { //glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) //glogger.Verbosity(3) @@ -2841,9 +2844,9 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { // This internally leads to a sidechain import, since the blocks trigger an // ErrPrunedAncestor error. // This may e.g. happen if -// 1. Downloader rollbacks a batch of inserted blocks and exits -// 2. Downloader starts to sync again -// 3. The blocks fetched are all known and canonical blocks +// 1. Downloader rollbacks a batch of inserted blocks and exits +// 2. Downloader starts to sync again +// 3. The blocks fetched are all known and canonical blocks func TestSideImportPrunedBlocks(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() @@ -2851,7 +2854,7 @@ func TestSideImportPrunedBlocks(t *testing.T) { genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) // Generate and import the canonical chain - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*int(DefaultCacheConfig.TriesInMemory), nil) diskdb := rawdb.NewMemoryDatabase() (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) @@ -2863,14 +2866,15 @@ func TestSideImportPrunedBlocks(t *testing.T) { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - lastPrunedIndex := len(blocks) - TriesInMemory - 1 + lastPrunedIndex := len(blocks) - int(chain.cacheConfig.TriesInMemory) - 1 lastPrunedBlock := blocks[lastPrunedIndex] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64()) } - firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] + + firstNonPrunedBlock := blocks[len(blocks)-int(chain.cacheConfig.TriesInMemory)] // Verify firstNonPrunedBlock is not pruned if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) @@ -3356,20 +3360,19 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { // TestInitThenFailCreateContract tests a pretty notorious case that happened // on mainnet over blocks 7338108, 7338110 and 7338115. -// - Block 7338108: address e771789f5cccac282f23bb7add5690e1f6ca467c is initiated -// with 0.001 ether (thus created but no code) -// - Block 7338110: a CREATE2 is attempted. The CREATE2 would deploy code on -// the same address e771789f5cccac282f23bb7add5690e1f6ca467c. However, the -// deployment fails due to OOG during initcode execution -// - Block 7338115: another tx checks the balance of -// e771789f5cccac282f23bb7add5690e1f6ca467c, and the snapshotter returned it as -// zero. +// - Block 7338108: address e771789f5cccac282f23bb7add5690e1f6ca467c is initiated +// with 0.001 ether (thus created but no code) +// - Block 7338110: a CREATE2 is attempted. The CREATE2 would deploy code on +// the same address e771789f5cccac282f23bb7add5690e1f6ca467c. However, the +// deployment fails due to OOG during initcode execution +// - Block 7338115: another tx checks the balance of +// e771789f5cccac282f23bb7add5690e1f6ca467c, and the snapshotter returned it as +// zero. // // The problem being that the snapshotter maintains a destructset, and adds items // to the destructset in case something is created "onto" an existing item. // We need to either roll back the snapDestructs, or not place it into snapDestructs // in the first place. -// func TestInitThenFailCreateContract(t *testing.T) { var ( // Generate a canonical chain to act as the main dataset @@ -3558,13 +3561,13 @@ func TestEIP2718Transition(t *testing.T) { // TestEIP1559Transition tests the following: // -// 1. A transaction whose gasFeeCap is greater than the baseFee is valid. -// 2. Gas accounting for access lists on EIP-1559 transactions is correct. -// 3. Only the transaction's tip will be received by the coinbase. -// 4. The transaction sender pays for both the tip and baseFee. -// 5. The coinbase receives only the partially realized tip when -// gasFeeCap - gasTipCap < baseFee. -// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). +// 1. A transaction whose gasFeeCap is greater than the baseFee is valid. +// 2. Gas accounting for access lists on EIP-1559 transactions is correct. +// 3. Only the transaction's tip will be received by the coinbase. +// 4. The transaction sender pays for both the tip and baseFee. +// 5. The coinbase receives only the partially realized tip when +// gasFeeCap - gasTipCap < baseFee. +// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). func TestEIP1559Transition(t *testing.T) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") diff --git a/core/forkchoice.go b/core/forkchoice.go index 9b7b60243d..018afdfac9 100644 --- a/core/forkchoice.go +++ b/core/forkchoice.go @@ -20,7 +20,7 @@ import ( "errors" "math/big" - "github.com/JekaMas/crand" + "github.com/maticnetwork/crand" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" diff --git a/core/tests/blockchain_sethead_test.go b/core/tests/blockchain_sethead_test.go index ad6e78697d..6160dfb48f 100644 --- a/core/tests/blockchain_sethead_test.go +++ b/core/tests/blockchain_sethead_test.go @@ -2082,6 +2082,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { // verifyNoGaps checks that there are no gaps after the initial set of blocks in // the database and errors if found. +// //nolint:gocognit func verifyNoGaps(t *testing.T, chain *core.BlockChain, canonical bool, inserted types.Blocks) { t.Helper() @@ -2135,6 +2136,7 @@ func verifyNoGaps(t *testing.T, chain *core.BlockChain, canonical bool, inserted // verifyCutoff checks that there are no chain data available in the chain after // the specified limit, but that it is available before. +// //nolint:gocognit func verifyCutoff(t *testing.T, chain *core.BlockChain, canonical bool, inserted types.Blocks, head int) { t.Helper() diff --git a/core/vm/interface.go b/core/vm/interface.go index ad9b05d666..1064adf590 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -74,6 +74,8 @@ type StateDB interface { AddPreimage(common.Hash, []byte) ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error + + Finalise(bool) } // CallContext provides a basic interface for the EVM calling conventions. The EVM diff --git a/docs/README.md b/docs/README.md index 95ba38b0da..5ebdbd7e26 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,18 +5,16 @@ - [Configuration file](./config.md) -## Deprecation notes +## Additional notes - The new entrypoint to run the Bor client is ```server```. -``` -$ bor server -``` + ``` + $ bor server + ``` -- Toml files to configure nodes are being deprecated. Currently, we only allow for static and trusted nodes to be configured using toml files. +- Toml files used earlier just to configure static/trusted nodes are being deprecated. Instead, a toml file now can be used instead of flags and can contain all configuration for the node to run. The link to a sample config file is given above. To simply run bor with a configuration file, the following command can be used. -``` -$ bor server --config ./legacy.toml -``` - -- ```Admin```, ```Personal``` and account related endpoints in ```Eth``` are being removed from the JsonRPC interface. Some of this functionality will be moved to the new GRPC server for operational tasks. + ``` + $ bor server --config + ``` diff --git a/docs/cli/server.md b/docs/cli/server.md index 5fe440b5fd..d52b135fa3 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -80,6 +80,8 @@ The ```bor server``` command runs the Bor client. - ```cache.preimages```: Enable recording the SHA3/keccak preimages of trie keys +- ```cache.triesinmemory```: Number of block states (tries) to keep in memory (default = 128) + - ```txlookuplimit```: Number of recent blocks to maintain transactions index for (default = about 56 days, 0 = entire chain) ### JsonRPC Options @@ -96,9 +98,7 @@ The ```bor server``` command runs the Bor client. - ```http.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. -- ```ws.corsdomain```: Comma separated list of domains from which to accept cross origin requests (browser enforced) - -- ```ws.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. +- ```ws.origins```: Origins from which to accept websockets requests - ```graphql.corsdomain```: Comma separated list of domains from which to accept cross origin requests (browser enforced) diff --git a/docs/config.md b/docs/config.md index aebd9e12b9..57f4c25fef 100644 --- a/docs/config.md +++ b/docs/config.md @@ -22,7 +22,7 @@ ethstats = "" ["eth.requiredblocks"] [p2p] -maxpeers = 30 +maxpeers = 50 maxpendpeers = 50 bind = "0.0.0.0" port = 30303 diff --git a/eth/backend.go b/eth/backend.go index cc65d9837f..824fec8914 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -218,6 +218,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { TrieTimeLimit: config.TrieTimeout, SnapshotLimit: config.SnapshotCache, Preimages: config.Preimages, + TriesInMemory: config.TriesInMemory, } ) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index adb36ffadd..c9272758ab 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -176,6 +176,7 @@ type Config struct { TrieTimeout time.Duration SnapshotCache int Preimages bool + TriesInMemory uint64 // Mining options Miner miner.Config diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 08c17601e4..3fce91ac9c 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -28,9 +28,11 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/bor/statefull" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" @@ -63,6 +65,8 @@ const ( defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024) ) +var defaultBorTraceEnabled = newBoolPtr(false) + // Backend interface provides the common API services (that are provided by // both full and light clients) with access to necessary functions. type Backend interface { @@ -80,6 +84,9 @@ type Backend interface { // so this method should be called with the parent. StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, preferDisk bool) (*state.StateDB, error) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) + + // Bor related APIs + GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) } // API is the collection of tracing APIs exposed over the private debugging endpoint. @@ -164,12 +171,33 @@ func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber return api.blockByHash(ctx, hash) } +// returns block transactions along with state-sync transaction if present +func (api *API) getAllBlockTransactions(ctx context.Context, block *types.Block) (types.Transactions, bool) { + txs := block.Transactions() + + stateSyncPresent := false + + borReceipt := rawdb.ReadBorReceipt(api.backend.ChainDb(), block.Hash(), block.NumberU64()) + if borReceipt != nil { + txHash := types.GetDerivedBorTxHash(types.BorReceiptKey(block.Number().Uint64(), block.Hash())) + if txHash != (common.Hash{}) { + borTx, _, _, _, _ := api.backend.GetBorBlockTransactionWithBlockHash(ctx, txHash, block.Hash()) + txs = append(txs, borTx) + stateSyncPresent = true + } + } + + return txs, stateSyncPresent +} + // TraceConfig holds extra parameters to trace functions. type TraceConfig struct { *logger.Config - Tracer *string - Timeout *string - Reexec *uint64 + Tracer *string + Timeout *string + Reexec *uint64 + BorTraceEnabled *bool + BorTx *bool } // TraceCallConfig is the config for traceCall API. It holds one more @@ -185,8 +213,9 @@ type TraceCallConfig struct { // StdTraceConfig holds extra parameters to standard-json trace functions. type StdTraceConfig struct { logger.Config - Reexec *uint64 - TxHash common.Hash + Reexec *uint64 + TxHash common.Hash + BorTraceEnabled *bool } // txTraceResult is the result of a single transaction trace. @@ -240,6 +269,16 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf // executes all the transactions contained within. The return value will be one item // per transaction, dependent on the requested tracer. func (api *API) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) { + if config == nil { + config = &TraceConfig{ + BorTraceEnabled: defaultBorTraceEnabled, + BorTx: newBoolPtr(false), + } + } + + if config.BorTraceEnabled == nil { + config.BorTraceEnabled = defaultBorTraceEnabled + } // Tracing a chain is a **long** operation, only do with subscriptions notifier, supported := rpc.NotifierFromContext(ctx) if !supported { @@ -274,19 +313,39 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number()) blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), nil) // Trace all the transactions contained within - for i, tx := range task.block.Transactions() { + txs, stateSyncPresent := api.getAllBlockTransactions(ctx, task.block) + if !*config.BorTraceEnabled && stateSyncPresent { + txs = txs[:len(txs)-1] + stateSyncPresent = false + } + + for i, tx := range txs { msg, _ := tx.AsMessage(signer, task.block.BaseFee()) txctx := &Context{ BlockHash: task.block.Hash(), TxIndex: i, TxHash: tx.Hash(), } - res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config) + + var res interface{} + + var err error + + if stateSyncPresent && i == len(txs)-1 { + if *config.BorTraceEnabled { + config.BorTx = newBoolPtr(true) + res, err = api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config) + } + } else { + res, err = api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config) + } + if err != nil { task.results[i] = &txTraceResult{Error: err.Error()} log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) break } + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number())) task.results[i] = &txTraceResult{Result: res} @@ -430,6 +489,11 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config return sub, nil } +func newBoolPtr(bb bool) *bool { + b := bb + return &b +} + // TraceBlockByNumber returns the structured logs created during the execution of // EVM and returns them as a JSON object. func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) { @@ -492,9 +556,35 @@ func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, return api.standardTraceBlockToFile(ctx, block, config) } +func prepareCallMessage(msg core.Message) statefull.Callmsg { + return statefull.Callmsg{ + CallMsg: ethereum.CallMsg{ + From: msg.From(), + To: msg.To(), + Gas: msg.Gas(), + GasPrice: msg.GasPrice(), + GasFeeCap: msg.GasFeeCap(), + GasTipCap: msg.GasTipCap(), + Value: msg.Value(), + Data: msg.Data(), + AccessList: msg.AccessList(), + }} +} + // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list // of intermediate roots: the stateroot after each transaction. func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) { + if config == nil { + config = &TraceConfig{ + BorTraceEnabled: defaultBorTraceEnabled, + BorTx: newBoolPtr(false), + } + } + + if config.BorTraceEnabled == nil { + config.BorTraceEnabled = defaultBorTraceEnabled + } + block, _ := api.blockByHash(ctx, hash) if block == nil { // Check in the bad blocks @@ -525,23 +615,47 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) ) - for i, tx := range block.Transactions() { + + txs, stateSyncPresent := api.getAllBlockTransactions(ctx, block) + for i, tx := range txs { var ( msg, _ = tx.AsMessage(signer, block.BaseFee()) txContext = core.NewEVMTxContext(msg) vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) ) statedb.Prepare(tx.Hash(), i) - if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { - log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) - // We intentionally don't return the error here: if we do, then the RPC server will not - // return the roots. Most likely, the caller already knows that a certain transaction fails to - // be included, but still want the intermediate roots that led to that point. - // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be - // executable. - // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. - return roots, nil + //nolint: nestif + if stateSyncPresent && i == len(txs)-1 { + if *config.BorTraceEnabled { + callmsg := prepareCallMessage(msg) + + if _, err := statefull.ApplyMessage(ctx, callmsg, statedb, block.Header(), api.backend.ChainConfig(), api.chainContext(ctx)); err != nil { + log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) + // We intentionally don't return the error here: if we do, then the RPC server will not + // return the roots. Most likely, the caller already knows that a certain transaction fails to + // be included, but still want the intermediate roots that led to that point. + // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be + // executable. + // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. + return roots, nil + } + } else { + break + } + } else { + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { + log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) + // We intentionally don't return the error here: if we do, then the RPC server will not + // return the roots. Most likely, the caller already knows that a certain transaction fails to + // be included, but still want the intermediate roots that led to that point. + // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be + // executable. + // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. + return roots, nil + } + } + // calling IntermediateRoot will internally call Finalize on the state // so any modifications are written to the trie roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects)) @@ -564,6 +678,18 @@ func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Has // executes all the transactions contained within. The return value will be one item // per transaction, dependent on the requestd tracer. func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { + + if config == nil { + config = &TraceConfig{ + BorTraceEnabled: defaultBorTraceEnabled, + BorTx: newBoolPtr(false), + } + } + + if config.BorTraceEnabled == nil { + config.BorTraceEnabled = defaultBorTraceEnabled + } + if block.NumberU64() == 0 { return nil, errors.New("genesis is not traceable") } @@ -581,9 +707,9 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac } // Execute all the transaction contained within the block concurrently var ( - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) - txs = block.Transactions() - results = make([]*txTraceResult, len(txs)) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + txs, stateSyncPresent = api.getAllBlockTransactions(ctx, block) + results = make([]*txTraceResult, len(txs)) pend = new(sync.WaitGroup) jobs = make(chan *txTraceTask, len(txs)) @@ -606,7 +732,21 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac TxIndex: task.index, TxHash: txs[task.index].Hash(), } - res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) + + var res interface{} + + var err error + + if stateSyncPresent && task.index == len(txs)-1 { + if *config.BorTraceEnabled { + config.BorTx = newBoolPtr(true) + res, err = api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) + } else { + break + } + } else { + res, err = api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) + } if err != nil { results[task.index] = &txTraceResult{Error: err.Error()} continue @@ -625,11 +765,26 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac // Generate the next state snapshot fast without tracing msg, _ := tx.AsMessage(signer, block.BaseFee()) statedb.Prepare(tx.Hash(), i) + vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) - if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { - failed = err - break + //nolint: nestif + if stateSyncPresent && i == len(txs)-1 { + if *config.BorTraceEnabled { + callmsg := prepareCallMessage(msg) + if _, err := statefull.ApplyBorMessage(*vmenv, callmsg); err != nil { + failed = err + break + } + } else { + break + } + } else { + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { + failed = err + break + } } + // Finalize the state so any modifications are written to the trie // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) @@ -641,16 +796,30 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac if failed != nil { return nil, failed } - return results, nil + + if !*config.BorTraceEnabled && stateSyncPresent { + return results[:len(results)-1], nil + } else { + return results, nil + } } // standardTraceBlockToFile configures a new tracer which uses standard JSON output, // and traces either a full block or an individual transaction. The return value will // be one filename per transaction traced. func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) { + if config == nil { + config = &StdTraceConfig{ + BorTraceEnabled: defaultBorTraceEnabled, + } + } + + if config.BorTraceEnabled == nil { + config.BorTraceEnabled = defaultBorTraceEnabled + } // If we're tracing a single transaction, make sure it's present if config != nil && config.TxHash != (common.Hash{}) { - if !containsTx(block, config.TxHash) { + if !api.containsTx(ctx, block, config.TxHash) { return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash) } } @@ -705,7 +874,14 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block canon = false } } - for i, tx := range block.Transactions() { + + txs, stateSyncPresent := api.getAllBlockTransactions(ctx, block) + if !*config.BorTraceEnabled && stateSyncPresent { + txs = txs[:len(txs)-1] + stateSyncPresent = false + } + + for i, tx := range txs { // Prepare the trasaction for un-traced execution var ( msg, _ = tx.AsMessage(signer, block.BaseFee()) @@ -739,10 +915,23 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) statedb.Prepare(tx.Hash(), i) - _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) - if writer != nil { - writer.Flush() + //nolint: nestif + if stateSyncPresent && i == len(txs)-1 { + if *config.BorTraceEnabled { + callmsg := prepareCallMessage(msg) + _, err = statefull.ApplyBorMessage(*vmenv, callmsg) + + if writer != nil { + writer.Flush() + } + } + } else { + _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) + if writer != nil { + writer.Flush() + } } + if dump != nil { dump.Close() log.Info("Wrote standard trace", "file", dump.Name()) @@ -764,8 +953,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // containsTx reports whether the transaction with a certain hash // is contained within the specified block. -func containsTx(block *types.Block, hash common.Hash) bool { - for _, tx := range block.Transactions() { +func (api *API) containsTx(ctx context.Context, block *types.Block, hash common.Hash) bool { + txs, _ := api.getAllBlockTransactions(ctx, block) + for _, tx := range txs { if tx.Hash() == hash { return true } @@ -776,6 +966,17 @@ func containsTx(block *types.Block, hash common.Hash) bool { // TraceTransaction returns the structured logs created during the execution of EVM // and returns them as a JSON object. func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { + if config == nil { + config = &TraceConfig{ + BorTraceEnabled: defaultBorTraceEnabled, + BorTx: newBoolPtr(false), + } + } + + if config.BorTraceEnabled == nil { + config.BorTraceEnabled = defaultBorTraceEnabled + } + tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash) if tx == nil { // For BorTransaction, there will be no trace available @@ -811,6 +1012,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * TxIndex: int(index), TxHash: hash, } + return api.traceTx(ctx, msg, txctx, vmctx, statedb, config) } @@ -865,6 +1067,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc Reexec: config.Reexec, } } + return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig) } @@ -872,6 +1075,18 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc // executes the given message in the provided environment. The return value will // be tracer dependent. func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { + + if config == nil { + config = &TraceConfig{ + BorTraceEnabled: defaultBorTraceEnabled, + BorTx: newBoolPtr(false), + } + } + + if config.BorTraceEnabled == nil { + config.BorTraceEnabled = defaultBorTraceEnabled + } + // Assemble the structured logger or the JavaScript tracer var ( tracer vm.EVMLogger @@ -911,9 +1126,22 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex // Call Prepare to clear out the statedb access list statedb.Prepare(txctx.TxHash, txctx.TxIndex) - result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) - if err != nil { - return nil, fmt.Errorf("tracing failed: %w", err) + var result *core.ExecutionResult + + if config.BorTx == nil { + config.BorTx = newBoolPtr(false) + } + + if *config.BorTx { + callmsg := prepareCallMessage(message) + if result, err = statefull.ApplyBorMessage(*vmenv, callmsg); err != nil { + return nil, fmt.Errorf("tracing failed: %w", err) + } + } else { + result, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) + if err != nil { + return nil, fmt.Errorf("tracing failed: %w", err) + } } // Depending on the tracer type, format and return the output. diff --git a/eth/tracers/api_bor.go b/eth/tracers/api_bor.go index f42c7a27f7..b93baae432 100644 --- a/eth/tracers/api_bor.go +++ b/eth/tracers/api_bor.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/bor/statefull" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -68,14 +69,14 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T // Execute all the transaction contained within the block concurrently var ( - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) - txs = block.Transactions() - deleteEmptyObjects = api.backend.ChainConfig().IsEIP158(block.Number()) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + txs, stateSyncPresent = api.getAllBlockTransactions(ctx, block) + deleteEmptyObjects = api.backend.ChainConfig().IsEIP158(block.Number()) ) blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - traceTxn := func(indx int, tx *types.Transaction) *TxTraceResult { + traceTxn := func(indx int, tx *types.Transaction, borTx bool) *TxTraceResult { message, _ := tx.AsMessage(signer, block.BaseFee()) txContext := core.NewEVMTxContext(message) @@ -88,7 +89,15 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T // Not sure if we need to do this statedb.Prepare(tx.Hash(), indx) - execRes, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) + var execRes *core.ExecutionResult + + if borTx { + callmsg := prepareCallMessage(message) + execRes, err = statefull.ApplyBorMessage(*vmenv, callmsg) + } else { + execRes, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) + } + if err != nil { return &TxTraceResult{ Error: err.Error(), @@ -115,7 +124,11 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T } for indx, tx := range txs { - res.Transactions = append(res.Transactions, traceTxn(indx, tx)) + if stateSyncPresent && indx == len(txs)-1 { + res.Transactions = append(res.Transactions, traceTxn(indx, tx, true)) + } else { + res.Transactions = append(res.Transactions, traceTxn(indx, tx, false)) + } } return res, nil diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index d2ed9c2179..6dd94e4870 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -176,6 +176,11 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } +func (b *testBackend) GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { + tx, blockHash, blockNumber, index := rawdb.ReadBorTransactionWithBlockHash(b.ChainDb(), txHash, blockHash) + return tx, blockHash, blockNumber, index, nil +} + func TestTraceCall(t *testing.T) { t.Parallel() diff --git a/go.mod b/go.mod index 18a2ca0ae7..36595ca307 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.19 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 github.com/BurntSushi/toml v1.1.0 - github.com/JekaMas/crand v1.0.1 github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d github.com/VictoriaMetrics/fastcache v1.6.0 github.com/aws/aws-sdk-go-v2 v1.2.0 @@ -47,6 +46,7 @@ require ( github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/usb v0.0.2 + github.com/maticnetwork/crand v1.0.2 github.com/maticnetwork/polyproto v0.0.2 github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-isatty v0.0.12 diff --git a/go.sum b/go.sum index dc419821c6..96fa9d3f04 100644 --- a/go.sum +++ b/go.sum @@ -29,8 +29,6 @@ github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/JekaMas/crand v1.0.1 h1:FMPxkUQqH/hExl0aUXsr0UCGYZ4lJH9IJ5H/KbM6Y9A= -github.com/JekaMas/crand v1.0.1/go.mod h1:GGzGpMCht/tbaNQ5A4kSiKSqEoNAhhyTfSDQyIENBQU= github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d h1:RO27lgfZF8s9lZ3pWyzc0gCE0RZC+6/PXbRjAa0CNp8= github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d/go.mod h1:romz7UPgSYhfJkKOalzEEyV6sWtt/eAEm0nX2aOrod0= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= @@ -345,6 +343,8 @@ github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/maticnetwork/crand v1.0.2 h1:Af0tAivC8zrxXDpGWNWVT/0s1fOz8w0eRbahZgURS8I= +github.com/maticnetwork/crand v1.0.2/go.mod h1:/NRNL3bj2eYdqpWmoIP5puxndTpi0XRxpj5ZKxfHjyg= github.com/maticnetwork/polyproto v0.0.2 h1:cPxuxbIDItdwGnucc3lZB58U8Zfe1mH73PWTGd15554= github.com/maticnetwork/polyproto v0.0.2/go.mod h1:e1mU2EXSwEpn5jM7GfNwu3AupsV6WAGoPFFfswXOF0o= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index e5e3a8b03e..b8310aea6f 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -266,6 +266,9 @@ type APIConfig struct { // Cors is the list of Cors endpoints Cors []string `hcl:"corsdomain,optional" toml:"corsdomain,optional"` + + // Origins is the list of endpoints to accept requests from (only consumed for websockets) + Origins []string `hcl:"origins,optional" toml:"origins,optional"` } type GpoConfig struct { @@ -364,6 +367,9 @@ type CacheConfig struct { // TxLookupLimit sets the maximum number of blocks from head whose tx indices are reserved. TxLookupLimit uint64 `hcl:"txlookuplimit,optional" toml:"txlookuplimit,optional"` + + // Number of block states to keep in memory (default = 128) + TriesInMemory uint64 `hcl:"triesinmemory,optional" toml:"triesinmemory,optional"` } type AccountsConfig struct { @@ -399,7 +405,7 @@ func DefaultConfig() *Config { LogLevel: "INFO", DataDir: DefaultDataDir(), P2P: &P2PConfig{ - MaxPeers: 30, + MaxPeers: 50, MaxPendPeers: 50, Bind: "0.0.0.0", Port: 30303, @@ -470,8 +476,7 @@ func DefaultConfig() *Config { Prefix: "", Host: "localhost", API: []string{"net", "web3"}, - Cors: []string{"localhost"}, - VHost: []string{"localhost"}, + Origins: []string{"localhost"}, }, Graphql: &APIConfig{ Enabled: false, @@ -509,6 +514,7 @@ func DefaultConfig() *Config { NoPrefetch: false, Preimages: false, TxLookupLimit: 2350000, + TriesInMemory: 128, }, Accounts: &AccountsConfig{ Unlock: []string{}, @@ -926,7 +932,7 @@ func (c *Config) buildNode() (*node.Config, error) { HTTPVirtualHosts: c.JsonRPC.Http.VHost, HTTPPathPrefix: c.JsonRPC.Http.Prefix, WSModules: c.JsonRPC.Ws.API, - WSOrigins: c.JsonRPC.Ws.Cors, + WSOrigins: c.JsonRPC.Ws.Origins, WSPathPrefix: c.JsonRPC.Ws.Prefix, GraphQLCors: c.JsonRPC.Graphql.Cors, GraphQLVirtualHosts: c.JsonRPC.Graphql.VHost, diff --git a/internal/cli/server/flags.go b/internal/cli/server/flags.go index 6e93a94de0..ba9be13376 100644 --- a/internal/cli/server/flags.go +++ b/internal/cli/server/flags.go @@ -304,6 +304,13 @@ func (c *Command) Flags() *flagset.Flagset { Default: c.cliConfig.Cache.Preimages, Group: "Cache", }) + f.Uint64Flag(&flagset.Uint64Flag{ + Name: "cache.triesinmemory", + Usage: "Number of block states (tries) to keep in memory (default = 128)", + Value: &c.cliConfig.Cache.TriesInMemory, + Default: c.cliConfig.Cache.TriesInMemory, + Group: "Cache", + }) f.Uint64Flag(&flagset.Uint64Flag{ Name: "txlookuplimit", Usage: "Number of recent blocks to maintain transactions index for (default = about 56 days, 0 = entire chain)", @@ -356,17 +363,10 @@ func (c *Command) Flags() *flagset.Flagset { Group: "JsonRPC", }) f.SliceStringFlag(&flagset.SliceStringFlag{ - Name: "ws.corsdomain", - Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", - Value: &c.cliConfig.JsonRPC.Ws.Cors, - Default: c.cliConfig.JsonRPC.Ws.Cors, - Group: "JsonRPC", - }) - f.SliceStringFlag(&flagset.SliceStringFlag{ - Name: "ws.vhosts", - Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", - Value: &c.cliConfig.JsonRPC.Ws.VHost, - Default: c.cliConfig.JsonRPC.Ws.VHost, + Name: "ws.origins", + Usage: "Origins from which to accept websockets requests", + Value: &c.cliConfig.JsonRPC.Ws.Origins, + Default: c.cliConfig.JsonRPC.Ws.Origins, Group: "JsonRPC", }) f.SliceStringFlag(&flagset.SliceStringFlag{ diff --git a/internal/cli/server/server.go b/internal/cli/server/server.go index 905de36e09..8d68fd69f0 100644 --- a/internal/cli/server/server.go +++ b/internal/cli/server/server.go @@ -36,6 +36,10 @@ import ( "github.com/ethereum/go-ethereum/metrics/influxdb" "github.com/ethereum/go-ethereum/metrics/prometheus" "github.com/ethereum/go-ethereum/node" + + // Force-load the tracer engines to trigger registration + _ "github.com/ethereum/go-ethereum/eth/tracers/js" + _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) type Server struct { @@ -253,6 +257,12 @@ func (s *Server) Stop() { } func (s *Server) setupMetrics(config *TelemetryConfig, serviceName string) error { + // Check the global metrics if they're matching with the provided config + if metrics.Enabled != config.Enabled || metrics.EnabledExpensive != config.Expensive { + log.Warn("Metric misconfiguration, some of them might not be visible") + } + + // Update the values anyways (for services which don't need immediate attention) metrics.Enabled = config.Enabled metrics.EnabledExpensive = config.Expensive @@ -263,6 +273,10 @@ func (s *Server) setupMetrics(config *TelemetryConfig, serviceName string) error log.Info("Enabling metrics collection") + if metrics.EnabledExpensive { + log.Info("Enabling expensive metrics collection") + } + // influxdb if v1Enabled, v2Enabled := config.InfluxDB.V1Enabled, config.InfluxDB.V2Enabled; v1Enabled || v2Enabled { if v1Enabled && v2Enabled { diff --git a/les/handler_test.go b/les/handler_test.go index aba45764b3..3ceabdf8ec 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -316,7 +316,7 @@ func TestGetStaleCodeLes4(t *testing.T) { testGetStaleCode(t, 4) } func testGetStaleCode(t *testing.T, protocol int) { netconfig := testnetConfig{ - blocks: core.TriesInMemory + 4, + blocks: int(core.DefaultCacheConfig.TriesInMemory) + 4, protocol: protocol, nopruning: true, } @@ -430,7 +430,7 @@ func TestGetStaleProofLes4(t *testing.T) { testGetStaleProof(t, 4) } func testGetStaleProof(t *testing.T, protocol int) { netconfig := testnetConfig{ - blocks: core.TriesInMemory + 4, + blocks: int(core.DefaultCacheConfig.TriesInMemory) + 4, protocol: protocol, nopruning: true, } diff --git a/les/peer.go b/les/peer.go index 499429739d..46a88cfff7 100644 --- a/les/peer.go +++ b/les/peer.go @@ -1058,7 +1058,7 @@ func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, ge // If local ethereum node is running in archive mode, advertise ourselves we have // all version state data. Otherwise only recent state is available. - stateRecent := uint64(core.TriesInMemory - blockSafetyMargin) + stateRecent := core.DefaultCacheConfig.TriesInMemory - blockSafetyMargin if server.archiveMode { stateRecent = 0 } diff --git a/les/server_requests.go b/les/server_requests.go index bab5f733d5..3595a6ab38 100644 --- a/les/server_requests.go +++ b/les/server_requests.go @@ -297,7 +297,7 @@ func handleGetCode(msg Decoder) (serveRequestFn, uint64, uint64, error) { // Refuse to search stale state data in the database since looking for // a non-exist key is kind of expensive. local := bc.CurrentHeader().Number.Uint64() - if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { + if !backend.ArchiveMode() && header.Number.Uint64()+core.DefaultCacheConfig.TriesInMemory <= local { p.Log().Debug("Reject stale code request", "number", header.Number.Uint64(), "head", local) p.bumpInvalid() continue @@ -396,7 +396,7 @@ func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { // Refuse to search stale state data in the database since looking for // a non-exist key is kind of expensive. local := bc.CurrentHeader().Number.Uint64() - if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { + if !backend.ArchiveMode() && header.Number.Uint64()+core.DefaultCacheConfig.TriesInMemory <= local { p.Log().Debug("Reject stale trie request", "number", header.Number.Uint64(), "head", local) p.bumpInvalid() continue diff --git a/les/test_helper.go b/les/test_helper.go index a099458353..1e6fb6653f 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -377,7 +377,7 @@ func (p *testPeer) handshakeWithClient(t *testing.T, td *big.Int, head common.Ha sendList = sendList.add("serveHeaders", nil) sendList = sendList.add("serveChainSince", uint64(0)) sendList = sendList.add("serveStateSince", uint64(0)) - sendList = sendList.add("serveRecentState", uint64(core.TriesInMemory-4)) + sendList = sendList.add("serveRecentState", core.DefaultCacheConfig.TriesInMemory-4) sendList = sendList.add("txRelay", nil) sendList = sendList.add("flowControl/BL", testBufLimit) sendList = sendList.add("flowControl/MRR", testBufRecharge) diff --git a/metrics/metrics.go b/metrics/metrics.go index 747d6471a7..1d0133e850 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/ethereum/go-ethereum/log" + "github.com/BurntSushi/toml" ) // Enabled is checked by the constructor functions for all of the @@ -32,26 +32,71 @@ var enablerFlags = []string{"metrics"} // expensiveEnablerFlags is the CLI flag names to use to enable metrics collections. var expensiveEnablerFlags = []string{"metrics.expensive"} +// configFlag is the CLI flag name to use to start node by providing a toml based config +var configFlag = "config" + // Init enables or disables the metrics system. Since we need this to run before // any other code gets to create meters and timers, we'll actually do an ugly hack // and peek into the command line args for the metrics flag. func init() { - for _, arg := range os.Args { + var configFile string + + for i := 0; i < len(os.Args); i++ { + arg := os.Args[i] + flag := strings.TrimLeft(arg, "-") + // check for existence of `config` flag + if flag == configFlag && i < len(os.Args)-1 { + configFile = strings.TrimLeft(os.Args[i+1], "-") // find the value of flag + } + for _, enabler := range enablerFlags { if !Enabled && flag == enabler { - log.Info("Enabling metrics collection") Enabled = true } } + for _, enabler := range expensiveEnablerFlags { if !EnabledExpensive && flag == enabler { - log.Info("Enabling expensive metrics collection") EnabledExpensive = true } } } + + // Update the global metrics value, if they're provided in the config file + updateMetricsFromConfig(configFile) +} + +func updateMetricsFromConfig(path string) { + // Don't act upon any errors here. They're already taken into + // consideration when the toml config file will be parsed in the cli. + data, err := os.ReadFile(path) + tomlData := string(data) + + if err != nil { + return + } + + // Create a minimal config to decode + type TelemetryConfig struct { + Enabled bool `hcl:"metrics,optional" toml:"metrics,optional"` + Expensive bool `hcl:"expensive,optional" toml:"expensive,optional"` + } + + type CliConfig struct { + Telemetry *TelemetryConfig `hcl:"telemetry,block" toml:"telemetry,block"` + } + + conf := &CliConfig{} + + if _, err := toml.Decode(tomlData, &conf); err != nil || conf == nil { + return + } + + // We have the values now, update them + Enabled = conf.Telemetry.Enabled + EnabledExpensive = conf.Telemetry.Expensive } // CollectProcessMetrics periodically collects various metrics about the running diff --git a/scripts/getconfig.go b/scripts/getconfig.go index 136b69ecab..caf3f45a8e 100644 --- a/scripts/getconfig.go +++ b/scripts/getconfig.go @@ -95,7 +95,7 @@ var flagMap = map[string][]string{ "override.arrowglacier": {"notABoolFlag", "No"}, "override.terminaltotaldifficulty": {"notABoolFlag", "No"}, "verbosity": {"notABoolFlag", "YesFV"}, - "ws.origins": {"notABoolFlag", "YesF"}, + "ws.origins": {"notABoolFlag", "No"}, } // map from cli flags to corresponding toml tags @@ -150,8 +150,7 @@ var nameTagMap = map[string]string{ "ipcpath": "ipcpath", "1-corsdomain": "http.corsdomain", "1-vhosts": "http.vhosts", - "2-corsdomain": "ws.corsdomain", - "2-vhosts": "ws.vhosts", + "origins": "ws.origins", "3-corsdomain": "graphql.corsdomain", "3-vhosts": "graphql.vhosts", "1-enabled": "http", @@ -226,9 +225,8 @@ var replacedFlagsMapFlagAndValue = map[string]map[string]map[string]string{ }, } -var replacedFlagsMapFlag = map[string]string{ - "ws.origins": "ws.corsdomain", -} +// Do not remove +var replacedFlagsMapFlag = map[string]string{} var currentBoolFlags = []string{ "snapshot", diff --git a/scripts/getconfig.sh b/scripts/getconfig.sh index 943d540a88..a2971c4f12 100755 --- a/scripts/getconfig.sh +++ b/scripts/getconfig.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/bin/bash set -e # Instructions: