diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 8f255143c52f..7a321e18b6b5 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -55,7 +55,7 @@ var ( } jsonFlag = cli.StringFlag{ Name: "combined-json", - Usage: "Path to the combined-json file generated by compiler", + Usage: "Path to the combined-json file generated by compiler, - for STDIN", } excFlag = cli.StringFlag{ Name: "exc", @@ -165,9 +165,18 @@ func abigen(c *cli.Context) error { var contracts map[string]*compiler.Contract if c.GlobalIsSet(jsonFlag.Name) { - jsonOutput, err := os.ReadFile(c.GlobalString(jsonFlag.Name)) + var ( + input = c.GlobalString(jsonFlag.Name) + jsonOutput []byte + err error + ) + if input == "-" { + jsonOutput, err = io.ReadAll(os.Stdin) + } else { + jsonOutput, err = os.ReadFile(input) + } if err != nil { - utils.Fatalf("Failed to read combined-json from compiler: %v", err) + utils.Fatalf("Failed to read combined-json: %v", err) } contracts, err = compiler.ParseCombinedJSON(jsonOutput, "", "", "", "") if err != nil { diff --git a/cmd/geth/config.go b/cmd/geth/config.go index bb003c4c1ae4..6d2bb2bcb622 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -164,7 +164,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { } backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Warn users to migrate if they have a legacy freezer format. - if eth != nil { + if eth != nil && !ctx.GlobalIsSet(utils.IgnoreLegacyReceiptsFlag.Name) { firstIdx := uint64(0) // Hack to speed up check for mainnet because we know // the first non-empty block. @@ -176,7 +176,8 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { if err != nil { log.Error("Failed to check db for legacy receipts", "err", err) } else if isLegacy { - log.Warn("Database has receipts with a legacy format. Please run `geth db freezer-migrate`.") + stack.Close() + utils.Fatalf("Database has receipts with a legacy format. Please run `geth db freezer-migrate`.") } } diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index ace2849c9f06..c4fe9251f9b8 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -307,7 +307,7 @@ func checkStateContent(ctx *cli.Context) error { start []byte ) if ctx.NArg() > 1 { - return fmt.Errorf("Max 1 argument: %v", ctx.Command.ArgsUsage) + return fmt.Errorf("max 1 argument: %v", ctx.Command.ArgsUsage) } if ctx.NArg() > 0 { if d, err := hexutil.Decode(ctx.Args().First()); err != nil { @@ -332,8 +332,8 @@ func checkStateContent(ctx *cli.Context) error { ) for it.Next() { count++ - v := it.Value() k := it.Key() + v := it.Value() hasher.Reset() hasher.Write(v) hasher.Read(got) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ea8a5187804f..1e2770ae808e 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -151,6 +151,7 @@ var ( utils.GpoMaxGasPriceFlag, utils.GpoIgnoreGasPriceFlag, utils.MinerNotifyFullFlag, + utils.IgnoreLegacyReceiptsFlag, configFileFlag, }, utils.NetworkFlags, utils.DatabasePathFlags) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 286eeed8ed2d..9ffc5918cc74 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -105,7 +105,7 @@ data, and verifies that all snapshot storage data has a corresponding account. }, { Name: "traverse-state", - Usage: "Traverse the state with given root hash for verification", + Usage: "Traverse the state with given root hash and perform quick verification", ArgsUsage: "", Action: utils.MigrateFlags(traverseState), Category: "MISCELLANEOUS COMMANDS", @@ -121,7 +121,7 @@ It's also usable without snapshot enabled. }, { Name: "traverse-rawstate", - Usage: "Traverse the state with given root hash for verification", + Usage: "Traverse the state with given root hash and perform detailed verification", ArgsUsage: "", Action: utils.MigrateFlags(traverseRawState), Category: "MISCELLANEOUS COMMANDS", @@ -367,6 +367,8 @@ func traverseRawState(ctx *cli.Context) error { codes int lastReport time.Time start = time.Now() + hasher = crypto.NewKeccakState() + got = make([]byte, 32) ) accIter := t.NodeIterator(nil) for accIter.Next(true) { @@ -376,10 +378,18 @@ func traverseRawState(ctx *cli.Context) error { // Check the present for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - if !rawdb.HasTrieNode(chaindb, node) { + blob := rawdb.ReadTrieNode(chaindb, node) + if len(blob) == 0 { log.Error("Missing trie node(account)", "hash", node) return errors.New("missing account") } + hasher.Reset() + hasher.Write(blob) + hasher.Read(got) + if !bytes.Equal(got, node.Bytes()) { + log.Error("Invalid trie node(account)", "hash", node.Hex(), "value", blob) + return errors.New("invalid account node") + } } // If it's a leaf node, yes we are touching an account, // dig into the storage trie further. @@ -404,10 +414,18 @@ func traverseRawState(ctx *cli.Context) error { // Check the present for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - if !rawdb.HasTrieNode(chaindb, node) { + blob := rawdb.ReadTrieNode(chaindb, node) + if len(blob) == 0 { log.Error("Missing trie node(storage)", "hash", node) return errors.New("missing storage") } + hasher.Reset() + hasher.Write(blob) + hasher.Read(got) + if !bytes.Equal(got, node.Bytes()) { + log.Error("Invalid trie node(storage)", "hash", node.Hex(), "value", blob) + return errors.New("invalid storage node") + } } // Bump the counter if it's leaf node. if storageIter.Leaf() { diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 731992ff7c21..56a3d053d640 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -227,6 +227,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ Flags: []cli.Flag{ utils.SnapshotFlag, utils.BloomFilterSizeFlag, + utils.IgnoreLegacyReceiptsFlag, cli.HelpFlag, }, }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 4ce16ef90031..0b28cd09f141 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -566,6 +566,10 @@ var ( Name: "nocompaction", Usage: "Disables db compaction after import", } + IgnoreLegacyReceiptsFlag = cli.BoolFlag{ + Name: "ignore-legacy-receipts", + Usage: "Geth will start up even if there are legacy receipts in freezer", + } // RPC settings IPCDisabledFlag = cli.BoolFlag{ Name: "ipcdisable", diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 685186817d2d..950300f03486 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -180,7 +180,7 @@ type Clique struct { signer common.Address // Ethereum address of the signing key signFn SignerFn // Signer function to authorize hashes with - lock sync.RWMutex // Protects the signer fields + lock sync.RWMutex // Protects the signer and proposals fields // The fields below are for testing only fakeDiff bool // Skip difficulty verifications @@ -507,9 +507,8 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header if err != nil { return err } + c.lock.RLock() if number%c.config.Epoch != 0 { - c.lock.RLock() - // Gather all the proposals that make sense voting on addresses := make([]common.Address, 0, len(c.proposals)) for address, authorize := range c.proposals { @@ -526,10 +525,14 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header copy(header.Nonce[:], nonceDropVote) } } - c.lock.RUnlock() } + + // Copy signer protected by mutex to avoid race condition + signer := c.signer + c.lock.RUnlock() + // Set the correct difficulty - header.Difficulty = calcDifficulty(snap, c.signer) + header.Difficulty = calcDifficulty(snap, signer) // Ensure the extra data has all its components if len(header.Extra) < extraVanity { @@ -666,7 +669,10 @@ func (c *Clique) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, if err != nil { return nil } - return calcDifficulty(snap, c.signer) + c.lock.RLock() + signer := c.signer + c.lock.RUnlock() + return calcDifficulty(snap, signer) } func calcDifficulty(snap *Snapshot, signer common.Address) *big.Int { diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index e18340b0f33e..e0216243f057 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -58,36 +58,36 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { return new(big.Int).SetUint64(params.InitialBaseFee) } - var ( - parentGasTarget = parent.GasLimit / params.ElasticityMultiplier - parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget) - baseFeeChangeDenominator = new(big.Int).SetUint64(params.BaseFeeChangeDenominator) - ) + parentGasTarget := parent.GasLimit / params.ElasticityMultiplier // If the parent gasUsed is the same as the target, the baseFee remains unchanged. if parent.GasUsed == parentGasTarget { return new(big.Int).Set(parent.BaseFee) } + + var ( + num = new(big.Int) + denom = new(big.Int) + ) + if parent.GasUsed > parentGasTarget { // If the parent block used more gas than its target, the baseFee should increase. - gasUsedDelta := new(big.Int).SetUint64(parent.GasUsed - parentGasTarget) - x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) - y := x.Div(x, parentGasTargetBig) - baseFeeDelta := math.BigMax( - x.Div(y, baseFeeChangeDenominator), - common.Big1, - ) + // max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator) + num.SetUint64(parent.GasUsed - parentGasTarget) + num.Mul(num, parent.BaseFee) + num.Div(num, denom.SetUint64(parentGasTarget)) + num.Div(num, denom.SetUint64(params.BaseFeeChangeDenominator)) + baseFeeDelta := math.BigMax(num, common.Big1) - return x.Add(parent.BaseFee, baseFeeDelta) + return num.Add(parent.BaseFee, baseFeeDelta) } else { // Otherwise if the parent block used less gas than its target, the baseFee should decrease. - gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parent.GasUsed) - x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) - y := x.Div(x, parentGasTargetBig) - baseFeeDelta := x.Div(y, baseFeeChangeDenominator) + // max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator) + num.SetUint64(parentGasTarget - parent.GasUsed) + num.Mul(num, parent.BaseFee) + num.Div(num, denom.SetUint64(parentGasTarget)) + num.Div(num, denom.SetUint64(params.BaseFeeChangeDenominator)) + baseFee := num.Sub(parent.BaseFee, num) - return math.BigMax( - x.Sub(parent.BaseFee, baseFeeDelta), - common.Big0, - ) + return math.BigMax(baseFee, common.Big0) } } diff --git a/contracts/checkpointoracle/oracle.go b/contracts/checkpointoracle/oracle.go index eff8ce2f2b80..dec01db24435 100644 --- a/contracts/checkpointoracle/oracle.go +++ b/contracts/checkpointoracle/oracle.go @@ -17,7 +17,8 @@ // Package checkpointoracle is a an on-chain light client checkpoint oracle. package checkpointoracle -//go:generate go run ../../cmd/abigen --sol contract/oracle.sol --pkg contract --out contract/oracle.go +//go:generate solc contract/oracle.sol --combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize -o ./ --overwrite +//go:generate go run ../../cmd/abigen --pkg contract --out contract/oracle.go --combined-json ./combined.json import ( "errors" diff --git a/core/beacon/types.go b/core/beacon/types.go index 18d5d2ab78b4..97bf66cd3fe4 100644 --- a/core/beacon/types.go +++ b/core/beacon/types.go @@ -148,6 +148,13 @@ func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) { if len(params.ExtraData) > 32 { return nil, fmt.Errorf("invalid extradata length: %v", len(params.ExtraData)) } + if len(params.LogsBloom) != 256 { + return nil, fmt.Errorf("invalid logsBloom length: %v", len(params.LogsBloom)) + } + // Check that baseFeePerGas is not negative or too big + if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { + return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) + } header := &types.Header{ ParentHash: params.ParentHash, UncleHash: types.EmptyUncleHash, diff --git a/core/blockchain.go b/core/blockchain.go index 5ac12303cf73..b8de2d484456 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1965,8 +1965,8 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { oldChain types.Blocks commonBlock *types.Block - deletedTxs types.Transactions - addedTxs types.Transactions + deletedTxs []common.Hash + addedTxs []common.Hash deletedLogs [][]*types.Log rebirthLogs [][]*types.Log @@ -1976,7 +1976,9 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // Old chain is longer, gather all transactions and logs as deleted ones for ; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) { oldChain = append(oldChain, oldBlock) - deletedTxs = append(deletedTxs, oldBlock.Transactions()...) + for _, tx := range oldBlock.Transactions() { + deletedTxs = append(deletedTxs, tx.Hash()) + } // Collect deleted logs for notification logs := bc.collectLogs(oldBlock.Hash(), true) @@ -2006,7 +2008,9 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } // Remove an old block as well as stash away a new block oldChain = append(oldChain, oldBlock) - deletedTxs = append(deletedTxs, oldBlock.Transactions()...) + for _, tx := range oldBlock.Transactions() { + deletedTxs = append(deletedTxs, tx.Hash()) + } // Collect deleted logs for notification logs := bc.collectLogs(oldBlock.Hash(), true) @@ -2025,6 +2029,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { return fmt.Errorf("invalid new chain") } } + // Ensure the user sees large reorgs if len(oldChain) > 0 && len(newChain) > 0 { logFn := log.Info @@ -2041,7 +2046,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } else if len(newChain) > 0 { // Special case happens in the post merge stage that current head is // the ancestor of new head while these two blocks are not consecutive - log.Info("Extend chain", "add", len(newChain), "number", newChain[0].NumberU64(), "hash", newChain[0].Hash()) + log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number(), "hash", newChain[0].Hash()) blockReorgAddMeter.Mark(int64(len(newChain))) } else { // len(newChain) == 0 && len(oldChain) > 0 @@ -2054,22 +2059,26 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // Insert the block in the canonical way, re-writing history bc.writeHeadBlock(newChain[i]) - // Collect reborn logs due to chain reorg - logs := bc.collectLogs(newChain[i].Hash(), false) - if len(logs) > 0 { - rebirthLogs = append(rebirthLogs, logs) - } // Collect the new added transactions. - addedTxs = append(addedTxs, newChain[i].Transactions()...) + for _, tx := range newChain[i].Transactions() { + addedTxs = append(addedTxs, tx.Hash()) + } } + // Delete useless indexes right now which includes the non-canonical // transaction indexes, canonical chain indexes which above the head. indexesBatch := bc.db.NewBatch() - for _, tx := range types.TxDifference(deletedTxs, addedTxs) { - rawdb.DeleteTxLookupEntry(indexesBatch, tx.Hash()) + for _, tx := range types.HashDifference(deletedTxs, addedTxs) { + rawdb.DeleteTxLookupEntry(indexesBatch, tx) + } + + // Delete all hash markers that are not part of the new canonical chain. + // Because the reorg function does not handle new chain head, all hash + // markers greater than or equal to new chain head should be deleted. + number := commonBlock.NumberU64() + if len(newChain) > 1 { + number = newChain[1].NumberU64() } - // Delete any canonical number assignments above the new head - number := bc.CurrentBlock().NumberU64() for i := number + 1; ; i++ { hash := rawdb.ReadCanonicalHash(bc.db, i) if hash == (common.Hash{}) { @@ -2080,6 +2089,15 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { if err := indexesBatch.Write(); err != nil { log.Crit("Failed to delete useless indexes", "err", err) } + + // Collect the logs + for i := len(newChain) - 1; i >= 1; i-- { + // Collect reborn logs due to chain reorg + logs := bc.collectLogs(newChain[i].Hash(), false) + if len(logs) > 0 { + rebirthLogs = append(rebirthLogs, logs) + } + } // If any logs need to be fired, do it now. In theory we could avoid creating // this goroutine if there are no events to fire, but realistcally that only // ever happens if we're reorging empty blocks, which will only happen on idle diff --git a/core/blockchain_test.go b/core/blockchain_test.go index b42f572b1290..28d3ccd9269b 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -3758,3 +3758,112 @@ func TestSetCanonical(t *testing.T) { chain.SetCanonical(canon[TriesInMemory-1]) verify(canon[TriesInMemory-1]) } + +// TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted +// correctly in case reorg is called. +func TestCanonicalHashMarker(t *testing.T) { + var cases = []struct { + forkA int + forkB int + }{ + // ForkA: 10 blocks + // ForkB: 1 blocks + // + // reorged: + // markers [2, 10] should be deleted + // markers [1] should be updated + {10, 1}, + + // ForkA: 10 blocks + // ForkB: 2 blocks + // + // reorged: + // markers [3, 10] should be deleted + // markers [1, 2] should be updated + {10, 2}, + + // ForkA: 10 blocks + // ForkB: 10 blocks + // + // reorged: + // markers [1, 10] should be updated + {10, 10}, + + // ForkA: 10 blocks + // ForkB: 11 blocks + // + // reorged: + // markers [1, 11] should be updated + {10, 11}, + } + for _, c := range cases { + var ( + db = rawdb.NewMemoryDatabase() + gspec = &Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + genesis = gspec.MustCommit(db) + engine = ethash.NewFaker() + ) + forkA, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, c.forkA, func(i int, gen *BlockGen) {}) + forkB, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, c.forkB, func(i int, gen *BlockGen) {}) + + // Initialize test chain + diskdb := rawdb.NewMemoryDatabase() + gspec.MustCommit(diskdb) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + // Insert forkA and forkB, the canonical should on forkA still + if n, err := chain.InsertChain(forkA); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + if n, err := chain.InsertChain(forkB); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + verify := func(head *types.Block) { + if chain.CurrentBlock().Hash() != head.Hash() { + t.Fatalf("Unexpected block hash, want %x, got %x", head.Hash(), chain.CurrentBlock().Hash()) + } + if chain.CurrentFastBlock().Hash() != head.Hash() { + t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentFastBlock().Hash()) + } + if chain.CurrentHeader().Hash() != head.Hash() { + t.Fatalf("Unexpected head header, want %x, got %x", head.Hash(), chain.CurrentHeader().Hash()) + } + if !chain.HasState(head.Root()) { + t.Fatalf("Lost block state %v %x", head.Number(), head.Hash()) + } + } + + // Switch canonical chain to forkB if necessary + if len(forkA) < len(forkB) { + verify(forkB[len(forkB)-1]) + } else { + verify(forkA[len(forkA)-1]) + chain.SetCanonical(forkB[len(forkB)-1]) + verify(forkB[len(forkB)-1]) + } + + // Ensure all hash markers are updated correctly + for i := 0; i < len(forkB); i++ { + block := forkB[i] + hash := chain.GetCanonicalHash(block.NumberU64()) + if hash != block.Hash() { + t.Fatalf("Unexpected canonical hash %d", block.NumberU64()) + } + } + if c.forkA > c.forkB { + for i := uint64(c.forkB) + 1; i <= uint64(c.forkA); i++ { + hash := chain.GetCanonicalHash(i) + if hash != (common.Hash{}) { + t.Fatalf("Unexpected canonical hash %d", i) + } + } + } + } +} diff --git a/core/evm.go b/core/evm.go index 536ac673e6a6..21e2639a5f63 100644 --- a/core/evm.go +++ b/core/evm.go @@ -84,6 +84,11 @@ func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash var cache []common.Hash return func(n uint64) common.Hash { + if ref.Number.Uint64() <= n { + // This situation can happen if we're doing tracing and using + // block overrides. + return common.Hash{} + } // If there's no hash cache yet, make one if len(cache) == 0 { cache = append(cache, ref.ParentHash) diff --git a/core/types/transaction.go b/core/types/transaction.go index 29820a0d785f..715ede15db2e 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -432,6 +432,24 @@ func TxDifference(a, b Transactions) Transactions { return keep } +// HashDifference returns a new set which is the difference between a and b. +func HashDifference(a, b []common.Hash) []common.Hash { + keep := make([]common.Hash, 0, len(a)) + + remove := make(map[common.Hash]struct{}) + for _, hash := range b { + remove[hash] = struct{}{} + } + + for _, hash := range a { + if _, ok := remove[hash]; !ok { + keep = append(keep, hash) + } + } + + return keep +} + // TxByNonce implements the sort interface to allow sorting a list of transactions // by their nonces. This is usually only useful for sorting transactions from a // single account, otherwise a nonce comparison doesn't make much sense. diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 3733bab6a7c0..4aa8cfe70f11 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -76,7 +76,7 @@ func codeBitmapInternal(code, bits bitvec) bitvec { for pc := uint64(0); pc < uint64(len(code)); { op := OpCode(code[pc]) pc++ - if op < PUSH1 || op > PUSH32 { + if int8(op) < int8(PUSH1) { // If not PUSH (the int8(op) > int(PUSH32) is always false). continue } numbits := op - PUSH1 + 1 diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 108ec412d9e3..4ed5093d831c 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -138,10 +138,14 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa log.Error("TDs unavailable for TTD check", "number", block.NumberU64(), "hash", update.HeadBlockHash, "td", td, "parent", block.ParentHash(), "ptd", ptd) return beacon.STATUS_INVALID, errors.New("TDs unavailable for TDD check") } - if td.Cmp(ttd) < 0 || (block.NumberU64() > 0 && ptd.Cmp(ttd) > 0) { + if td.Cmp(ttd) < 0 { log.Error("Refusing beacon update to pre-merge", "number", block.NumberU64(), "hash", update.HeadBlockHash, "diff", block.Difficulty(), "age", common.PrettyAge(time.Unix(int64(block.Time()), 0))) return beacon.ForkChoiceResponse{PayloadStatus: beacon.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil } + if block.NumberU64() > 0 && ptd.Cmp(ttd) >= 0 { + log.Error("Parent block is already post-ttd", "number", block.NumberU64(), "hash", update.HeadBlockHash, "diff", block.Difficulty(), "age", common.PrettyAge(time.Unix(int64(block.Time()), 0))) + return beacon.ForkChoiceResponse{PayloadStatus: beacon.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil + } } if rawdb.ReadCanonicalHash(api.eth.ChainDb(), block.NumberU64()) != update.HeadBlockHash { @@ -295,11 +299,16 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa // We have an existing parent, do some sanity checks to avoid the beacon client // triggering too early var ( - td = api.eth.BlockChain().GetTd(parent.Hash(), parent.NumberU64()) - ttd = api.eth.BlockChain().Config().TerminalTotalDifficulty + ptd = api.eth.BlockChain().GetTd(parent.Hash(), parent.NumberU64()) + ttd = api.eth.BlockChain().Config().TerminalTotalDifficulty + gptd = api.eth.BlockChain().GetTd(parent.ParentHash(), parent.NumberU64()-1) ) - if td.Cmp(ttd) < 0 { - log.Warn("Ignoring pre-merge payload", "number", params.Number, "hash", params.BlockHash, "td", td, "ttd", ttd) + if ptd.Cmp(ttd) < 0 { + log.Warn("Ignoring pre-merge payload", "number", params.Number, "hash", params.BlockHash, "td", ptd, "ttd", ttd) + return beacon.INVALID_TERMINAL_BLOCK, nil + } + if parent.Difficulty().BitLen() > 0 && gptd != nil && gptd.Cmp(ttd) >= 0 { + log.Error("Ignoring pre-merge parent block", "number", params.Number, "hash", params.BlockHash, "td", ptd, "ttd", ttd) return beacon.INVALID_TERMINAL_BLOCK, nil } if block.Time() <= parent.Time() { @@ -345,7 +354,12 @@ func computePayloadId(headBlockHash common.Hash, params *beacon.PayloadAttribute func (api *ConsensusAPI) invalid(err error, latestValid *types.Block) beacon.PayloadStatusV1 { currentHash := api.eth.BlockChain().CurrentBlock().Hash() if latestValid != nil { - currentHash = latestValid.Hash() + // Set latest valid hash to 0x0 if parent is PoW block + currentHash = common.Hash{} + if latestValid.Difficulty().BitLen() == 0 { + // Otherwise set latest valid hash to parent hash + currentHash = latestValid.Hash() + } } errorMsg := err.Error() return beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: ¤tHash, ValidationError: &errorMsg} diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 415506d58e50..6171c14c432c 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -205,7 +205,6 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan co func TestInvalidPayloadTimestamp(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, preMergeBlocks) - ethservice.Merger().ReachTTD() defer n.Close() var ( api = NewConsensusAPI(ethservice) @@ -250,7 +249,6 @@ func TestInvalidPayloadTimestamp(t *testing.T) { func TestEth2NewBlock(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, preMergeBlocks) - ethservice.Merger().ReachTTD() defer n.Close() var ( @@ -427,7 +425,6 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) func TestFullAPI(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, preMergeBlocks) - ethservice.Merger().ReachTTD() defer n.Close() var ( parent = ethservice.BlockChain().CurrentBlock() @@ -480,7 +477,6 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Bl func TestExchangeTransitionConfig(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, preMergeBlocks) - ethservice.Merger().ReachTTD() defer n.Close() var ( api = NewConsensusAPI(ethservice) @@ -543,7 +539,6 @@ CommonAncestor◄─▲── P1 ◄── P2 ◄─ P3 ◄─ ... ◄─ Pn func TestNewPayloadOnInvalidChain(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, preMergeBlocks) - ethservice.Merger().ReachTTD() defer n.Close() var ( @@ -618,7 +613,6 @@ func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.Pay func TestEmptyBlocks(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, preMergeBlocks) - ethservice.Merger().ReachTTD() defer n.Close() commonAncestor := ethservice.BlockChain().CurrentBlock() @@ -653,7 +647,8 @@ func TestEmptyBlocks(t *testing.T) { if status.Status != beacon.INVALID { t.Errorf("invalid status: expected INVALID got: %v", status.Status) } - expected := commonAncestor.Hash() + // Expect 0x0 on INVALID block on top of PoW block + expected := common.Hash{} if !bytes.Equal(status.LatestValidHash[:], expected[:]) { t.Fatalf("invalid LVH: got %v want %v", status.LatestValidHash, expected) } @@ -734,8 +729,6 @@ func TestTrickRemoteBlockCache(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks) nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks) - ethserviceA.Merger().ReachTTD() - ethserviceB.Merger().ReachTTD() defer nodeA.Close() defer nodeB.Close() for nodeB.Server().NodeInfo().Ports.Listener == 0 { @@ -794,3 +787,75 @@ func TestTrickRemoteBlockCache(t *testing.T) { time.Sleep(100 * time.Millisecond) } } + +func TestInvalidBloom(t *testing.T) { + genesis, preMergeBlocks := generatePreMergeChain(10) + n, ethservice := startEthService(t, genesis, preMergeBlocks) + ethservice.Merger().ReachTTD() + defer n.Close() + + commonAncestor := ethservice.BlockChain().CurrentBlock() + api := NewConsensusAPI(ethservice) + + // Setup 10 blocks on the canonical chain + setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {}) + + // (1) check LatestValidHash by sending a normal payload (P1'') + payload := getNewPayload(t, api, commonAncestor) + payload.LogsBloom = append(payload.LogsBloom, byte(1)) + status, err := api.NewPayloadV1(*payload) + if err != nil { + t.Fatal(err) + } + if status.Status != beacon.INVALIDBLOCKHASH { + t.Errorf("invalid status: expected VALID got: %v", status.Status) + } +} + +func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { + genesis, preMergeBlocks := generatePreMergeChain(100) + fmt.Println(genesis.Config.TerminalTotalDifficulty) + genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) + + fmt.Println(genesis.Config.TerminalTotalDifficulty) + n, ethservice := startEthService(t, genesis, preMergeBlocks) + defer n.Close() + + var ( + api = NewConsensusAPI(ethservice) + parent = preMergeBlocks[len(preMergeBlocks)-1] + ) + + // Test parent already post TTD in FCU + fcState := beacon.ForkchoiceStateV1{ + HeadBlockHash: parent.Hash(), + SafeBlockHash: common.Hash{}, + FinalizedBlockHash: common.Hash{}, + } + resp, err := api.ForkchoiceUpdatedV1(fcState, nil) + if err != nil { + t.Fatalf("error sending forkchoice, err=%v", err) + } + if resp.PayloadStatus != beacon.INVALID_TERMINAL_BLOCK { + t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) + } + + // Test parent already post TTD in NewPayload + params := beacon.PayloadAttributesV1{ + Timestamp: parent.Time() + 1, + Random: crypto.Keccak256Hash([]byte{byte(1)}), + SuggestedFeeRecipient: parent.Coinbase(), + } + empty, err := api.eth.Miner().GetSealingBlockSync(parent.Hash(), params.Timestamp, params.SuggestedFeeRecipient, params.Random, true) + if err != nil { + t.Fatalf("error preparing payload, err=%v", err) + } + data := *beacon.BlockToExecutableData(empty) + resp2, err := api.NewPayloadV1(data) + if err != nil { + t.Fatalf("error sending NewPayload, err=%v", err) + } + if resp2 != beacon.INVALID_TERMINAL_BLOCK { + t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) + } +} diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 87971d5a97c9..8d145d960432 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -592,7 +592,7 @@ func TestPendingLogsSubscription(t *testing.T) { // (some) events are posted. for i := range testCases { testCases[i].c = make(chan []*types.Log) - testCases[i].err = make(chan error) + testCases[i].err = make(chan error, 1) var err error testCases[i].sub, err = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 074f193e64eb..13b89885138e 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -179,6 +179,7 @@ type TraceCallConfig struct { Timeout *string Reexec *uint64 StateOverrides *ethapi.StateOverride + BlockOverrides *ethapi.BlockOverrides } // StdTraceConfig holds extra parameters to standard-json trace functions. @@ -806,7 +807,6 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * // TraceCall lets you trace a given eth_call. It collects the structured logs // created during the execution of EVM if the given transaction was added on // top of the provided block and returns them as a JSON object. -// You can provide -2 as a block number to trace on top of the pending block. func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) { // Try to retrieve the specified block var ( @@ -816,6 +816,14 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc if hash, ok := blockNrOrHash.Hash(); ok { block, err = api.blockByHash(ctx, hash) } else if number, ok := blockNrOrHash.Number(); ok { + if number == rpc.PendingBlockNumber { + // We don't have access to the miner here. For tracing 'future' transactions, + // it can be done with block- and state-overrides instead, which offers + // more flexibility and stability than trying to trace on 'pending', since + // the contents of 'pending' is unstable and probably not a true representation + // of what the next actual block is likely to contain. + return nil, errors.New("tracing on top of pending is not supported") + } block, err = api.blockByNumber(ctx, number) } else { return nil, errors.New("invalid arguments; neither block nor hash specified") @@ -832,18 +840,19 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc if err != nil { return nil, err } - // Apply the customized state rules if required. + vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + // Apply the customization rules if required. if config != nil { if err := config.StateOverrides.Apply(statedb); err != nil { return nil, err } + config.BlockOverrides.Apply(&vmctx) } // Execute the trace msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee()) if err != nil { return nil, err } - vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) var traceConfig *TraceConfig if config != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index af41f05d212b..bc12b9275160 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -196,13 +196,12 @@ func TestTraceCall(t *testing.T) { tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) b.AddTx(tx) })) - var testSuite = []struct { blockNumber rpc.BlockNumber call ethapi.TransactionArgs config *TraceCallConfig expectErr error - expect interface{} + expect string }{ // Standard JSON trace upon the genesis, plain transfer. { @@ -214,12 +213,7 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: &logger.ExecutionResult{ - Gas: params.TxGas, - Failed: false, - ReturnValue: "", - StructLogs: []logger.StructLogRes{}, - }, + expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, }, // Standard JSON trace upon the head, plain transfer. { @@ -231,12 +225,7 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: &logger.ExecutionResult{ - Gas: params.TxGas, - Failed: false, - ReturnValue: "", - StructLogs: []logger.StructLogRes{}, - }, + expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, }, // Standard JSON trace upon the non-existent block, error expects { @@ -248,7 +237,7 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: fmt.Errorf("block #%d not found", genBlocks+1), - expect: nil, + //expect: nil, }, // Standard JSON trace upon the latest block { @@ -260,14 +249,9 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: &logger.ExecutionResult{ - Gas: params.TxGas, - Failed: false, - ReturnValue: "", - StructLogs: []logger.StructLogRes{}, - }, + expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, }, - // Standard JSON trace upon the pending block + // Tracing on 'pending' should fail: { blockNumber: rpc.PendingBlockNumber, call: ethapi.TransactionArgs{ @@ -276,36 +260,48 @@ func TestTraceCall(t *testing.T) { Value: (*hexutil.Big)(big.NewInt(1000)), }, config: nil, - expectErr: nil, - expect: &logger.ExecutionResult{ - Gas: params.TxGas, - Failed: false, - ReturnValue: "", - StructLogs: []logger.StructLogRes{}, + expectErr: errors.New("tracing on top of pending is not supported"), + }, + { + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &accounts[0].addr, + Input: &hexutil.Bytes{0x43}, // blocknumber + }, + config: &TraceCallConfig{ + BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, }, + expectErr: nil, + expect: ` {"gas":53018,"failed":false,"returnValue":"","structLogs":[ + {"pc":0,"op":"NUMBER","gas":24946984,"gasCost":2,"depth":1,"stack":[]}, + {"pc":1,"op":"STOP","gas":24946982,"gasCost":0,"depth":1,"stack":["0x1337"]}]}`, }, } - for _, testspec := range testSuite { + for i, testspec := range testSuite { result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config) if testspec.expectErr != nil { if err == nil { - t.Errorf("Expect error %v, get nothing", testspec.expectErr) + t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr) continue } if !reflect.DeepEqual(err, testspec.expectErr) { - t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err) + t.Errorf("test %d: error mismatch, want %v, git %v", i, testspec.expectErr, err) } } else { if err != nil { - t.Errorf("Expect no error, get %v", err) + t.Errorf("test %d: expect no error, got %v", i, err) continue } var have *logger.ExecutionResult if err := json.Unmarshal(result.(json.RawMessage), &have); err != nil { - t.Errorf("failed to unmarshal result %v", err) + t.Errorf("test %d: failed to unmarshal result %v", i, err) + } + var want *logger.ExecutionResult + if err := json.Unmarshal([]byte(testspec.expect), &want); err != nil { + t.Errorf("test %d: failed to unmarshal result %v", i, err) } - if !reflect.DeepEqual(have, testspec.expect) { - t.Errorf("Result mismatch, want %v, get %v", testspec.expect, have) + if !reflect.DeepEqual(have, want) { + t.Errorf("test %d: result mismatch, want %v, got %v", i, testspec.expect, string(result.(json.RawMessage))) } } } @@ -446,7 +442,7 @@ func TestTracingWithOverrides(t *testing.T) { type res struct { Gas int Failed bool - returnValue string + ReturnValue string } var testSuite = []struct { blockNumber rpc.BlockNumber @@ -457,7 +453,7 @@ func TestTracingWithOverrides(t *testing.T) { }{ // Call which can only succeed if state is state overridden { - blockNumber: rpc.PendingBlockNumber, + blockNumber: rpc.LatestBlockNumber, call: ethapi.TransactionArgs{ From: &randomAccounts[0].addr, To: &randomAccounts[1].addr, @@ -472,7 +468,7 @@ func TestTracingWithOverrides(t *testing.T) { }, // Invalid call without state overriding { - blockNumber: rpc.PendingBlockNumber, + blockNumber: rpc.LatestBlockNumber, call: ethapi.TransactionArgs{ From: &randomAccounts[0].addr, To: &randomAccounts[1].addr, @@ -498,7 +494,7 @@ func TestTracingWithOverrides(t *testing.T) { // } // } { - blockNumber: rpc.PendingBlockNumber, + blockNumber: rpc.LatestBlockNumber, call: ethapi.TransactionArgs{ From: &randomAccounts[0].addr, To: &randomAccounts[2].addr, @@ -515,6 +511,39 @@ func TestTracingWithOverrides(t *testing.T) { }, want: `{"gas":23347,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`, }, + { // Override blocknumber + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &accounts[0].addr, + // BLOCKNUMBER PUSH1 MSTORE + Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")), + //&hexutil.Bytes{0x43}, // blocknumber + }, + config: &TraceCallConfig{ + BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, + }, + want: `{"gas":59537,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000001337"}`, + }, + { // Override blocknumber, and query a blockhash + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &accounts[0].addr, + Input: &hexutil.Bytes{ + 0x60, 0x00, 0x40, // BLOCKHASH(0) + 0x60, 0x00, 0x52, // STORE memory offset 0 + 0x61, 0x13, 0x36, 0x40, // BLOCKHASH(0x1336) + 0x60, 0x20, 0x52, // STORE memory offset 32 + 0x61, 0x13, 0x37, 0x40, // BLOCKHASH(0x1337) + 0x60, 0x40, 0x52, // STORE memory offset 64 + 0x60, 0x60, 0x60, 0x00, 0xf3, // RETURN (0-96) + + }, // blocknumber + }, + config: &TraceCallConfig{ + BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, + }, + want: `{"gas":72666,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`, + }, } for i, tc := range testSuite { result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config) diff --git a/go.mod b/go.mod index efbd82f511ba..fc944282f2d7 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,9 @@ module github.com/ethereum/go-ethereum -go 1.16 +go 1.17 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 - github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 github.com/aws/aws-sdk-go-v2 v1.2.0 github.com/aws/aws-sdk-go-v2/config v1.1.1 @@ -16,15 +15,13 @@ require ( github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.8.0 - github.com/deepmap/oapi-codegen v1.8.2 // indirect - github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf + github.com/docker/docker v1.6.2 github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf github.com/edsrzf/mmap-go v1.0.0 github.com/fatih/color v1.7.0 github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-stack/stack v1.8.0 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.4.3 @@ -40,15 +37,12 @@ require ( github.com/huin/goupnp v1.0.3 github.com/influxdata/influxdb v1.8.3 github.com/influxdata/influxdb-client-go/v2 v2.4.0 - github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.2.0 github.com/karalabe/usb v0.0.2 - github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-isatty v0.0.12 - github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 @@ -58,8 +52,8 @@ require ( github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 github.com/stretchr/testify v1.7.0 + github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 @@ -70,5 +64,40 @@ require ( golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/urfave/cli.v1 v1.20.0 - gotest.tools v2.2.0+incompatible // indirect +) + +require ( + github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect + github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect + github.com/aws/smithy-go v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + 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-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/kylelemons/godebug v1.1.0 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect + github.com/naoina/go-stringutil v0.1.0 // indirect + github.com/opentracing/opentracing-go v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/tklauser/go-sysconf v0.3.5 // indirect + github.com/tklauser/numcpus v0.2.2 // indirect + golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect + golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/protobuf v1.23.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index f77e58cdd543..8d28443f6c61 100644 --- a/go.sum +++ b/go.sum @@ -106,8 +106,8 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmakYiSlqu2425CHyFXLZZnvm7PDpU8M= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.6.2 h1:HlFGsy+9/xrgMmhmN+NGhCc5SHGJ7I+kHosRR1xc/aI= +github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= @@ -384,6 +384,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= @@ -652,8 +654,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1b7c17786747..7c422e642d70 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -888,6 +888,41 @@ func (diff *StateOverride) Apply(state *state.StateDB) error { return nil } +// BlockOverrides is a set of header fields to override. +type BlockOverrides struct { + Number *hexutil.Big + Difficulty *hexutil.Big + Time *hexutil.Big + GasLimit *hexutil.Uint64 + Coinbase *common.Address + Random *common.Hash +} + +// Apply overrides the given header fields into the given block context. +func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) { + if diff == nil { + return + } + if diff.Number != nil { + blockCtx.BlockNumber = diff.Number.ToInt() + } + if diff.Difficulty != nil { + blockCtx.Difficulty = diff.Difficulty.ToInt() + } + if diff.Time != nil { + blockCtx.Time = diff.Time.ToInt() + } + if diff.GasLimit != nil { + blockCtx.GasLimit = uint64(*diff.GasLimit) + } + if diff.Coinbase != nil { + blockCtx.Coinbase = *diff.Coinbase + } + if diff.Random != nil { + blockCtx.Random = diff.Random + } +} + func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index c7dba8a1ef0d..229a5b5e53ba 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -314,6 +314,11 @@ func TestJWT(t *testing.T) { ss, _ := jwt.NewWithClaims(method, testClaim(input)).SignedString(secret) return ss } + srv := createAndStartServer(t, &httpConfig{jwtSecret: []byte("secret")}, + true, &wsConfig{Origins: []string{"*"}, jwtSecret: []byte("secret")}) + wsUrl := fmt.Sprintf("ws://%v", srv.listenAddr()) + htUrl := fmt.Sprintf("http://%v", srv.listenAddr()) + expOk := []string{ fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + 4})), @@ -327,6 +332,14 @@ func TestJWT(t *testing.T) { "bar": "baz", })), } + for i, token := range expOk { + if err := wsRequest(t, wsUrl, "Authorization", token); err != nil { + t.Errorf("test %d-ws, token '%v': expected ok, got %v", i, token, err) + } + if resp := rpcRequest(t, htUrl, "Authorization", token); resp.StatusCode != 200 { + t.Errorf("test %d-http, token '%v': expected ok, got %v", i, token, resp.StatusCode) + } + } expFail := []string{ // future fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + 6})), @@ -351,19 +364,6 @@ func TestJWT(t *testing.T) { fmt.Sprintf("Bearer\t%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), fmt.Sprintf("Bearer \t%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), } - srv := createAndStartServer(t, &httpConfig{jwtSecret: []byte("secret")}, - true, &wsConfig{Origins: []string{"*"}, jwtSecret: []byte("secret")}) - wsUrl := fmt.Sprintf("ws://%v", srv.listenAddr()) - htUrl := fmt.Sprintf("http://%v", srv.listenAddr()) - - for i, token := range expOk { - if err := wsRequest(t, wsUrl, "Authorization", token); err != nil { - t.Errorf("test %d-ws, token '%v': expected ok, got %v", i, token, err) - } - if resp := rpcRequest(t, htUrl, "Authorization", token); resp.StatusCode != 200 { - t.Errorf("test %d-http, token '%v': expected ok, got %v", i, token, resp.StatusCode) - } - } for i, token := range expFail { if err := wsRequest(t, wsUrl, "Authorization", token); err == nil { t.Errorf("tc %d-ws, token '%v': expected not to allow, got ok", i, token) diff --git a/params/config.go b/params/config.go index 3533bf1c7918..0f8b8a7cb417 100644 --- a/params/config.go +++ b/params/config.go @@ -114,7 +114,7 @@ var ( MuirGlacierBlock: big.NewInt(7_117_117), BerlinBlock: big.NewInt(9_812_189), LondonBlock: big.NewInt(10_499_401), - TerminalTotalDifficulty: big.NewInt(43531756765713534), + TerminalTotalDifficulty: new(big.Int).SetBytes([]byte{0x15, 0x2D, 0x02, 0xC7, 0xE1, 0x4A, 0xF6, 0x80, 0x00, 0x00}), // 100_000_000_000_000_000_000_000 Ethash: new(EthashConfig), } diff --git a/params/version.go b/params/version.go index 2530acf4656a..8c8b6295a8f0 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 = 18 // Patch version component of the current release + VersionPatch = 19 // Patch version component of the current release VersionMeta = "unstable" // Version metadata to append to the version string ) diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index b283ed11fe39..c511c6501132 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -30,19 +30,20 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/ethereum/go-ethereum/crypto/bls12381" + blst "github.com/supranational/blst/bindings/go" ) func FuzzCrossPairing(data []byte) int { input := bytes.NewReader(data) // get random G1 points - kpG1, cpG1, err := getG1Points(input) + kpG1, cpG1, blG1, err := getG1Points(input) if err != nil { return 0 } // get random G2 points - kpG2, cpG2, err := getG2Points(input) + kpG2, cpG2, blG2, err := getG2Points(input) if err != nil { return 0 } @@ -63,6 +64,15 @@ func FuzzCrossPairing(data []byte) int { panic("pairing mismatch gnark / geth ") } + var b []byte + ctx := blst.PairingCtx(false, b) + // compute pairing using blst + blst.PairingRawAggregate(ctx, blG2, blG1) + blstResult := blst.PairingAsFp12(ctx) + if !(bytes.Equal(blstResult.ToBendian(), bls12381.NewGT().ToBytes(kResult))) { + panic("pairing mismatch blst / geth ") + } + return 1 } @@ -70,13 +80,13 @@ func FuzzCrossG1Add(data []byte) int { input := bytes.NewReader(data) // get random G1 points - kp1, cp1, err := getG1Points(input) + kp1, cp1, bl1, err := getG1Points(input) if err != nil { return 0 } // get random G1 points - kp2, cp2, err := getG1Points(input) + kp2, cp2, bl2, err := getG1Points(input) if err != nil { return 0 } @@ -96,6 +106,11 @@ func FuzzCrossG1Add(data []byte) int { panic("G1 point addition mismatch gnark / geth ") } + bl3 := blst.P1AffinesAdd([]*blst.P1Affine{bl1, bl2}) + if !(bytes.Equal(cp.Marshal(), bl3.Serialize())) { + panic("G1 point addition mismatch blst / geth ") + } + return 1 } @@ -103,13 +118,13 @@ func FuzzCrossG2Add(data []byte) int { input := bytes.NewReader(data) // get random G2 points - kp1, cp1, err := getG2Points(input) + kp1, cp1, bl1, err := getG2Points(input) if err != nil { return 0 } // get random G2 points - kp2, cp2, err := getG2Points(input) + kp2, cp2, bl2, err := getG2Points(input) if err != nil { return 0 } @@ -129,6 +144,11 @@ func FuzzCrossG2Add(data []byte) int { panic("G2 point addition mismatch gnark / geth ") } + bl3 := blst.P2AffinesAdd([]*blst.P2Affine{bl1, bl2}) + if !(bytes.Equal(cp.Marshal(), bl3.Serialize())) { + panic("G1 point addition mismatch blst / geth ") + } + return 1 } @@ -148,7 +168,7 @@ func FuzzCrossG1MultiExp(data []byte) int { break } // get a random G1 point as basis - kp1, cp1, err := getG1Points(input) + kp1, cp1, _, err := getG1Points(input) if err != nil { break } @@ -183,11 +203,11 @@ func FuzzCrossG1MultiExp(data []byte) int { return 1 } -func getG1Points(input io.Reader) (*bls12381.PointG1, *gnark.G1Affine, error) { +func getG1Points(input io.Reader) (*bls12381.PointG1, *gnark.G1Affine, *blst.P1Affine, error) { // sample a random scalar s, err := randomScalar(input, fp.Modulus()) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // compute a random point @@ -206,14 +226,23 @@ func getG1Points(input io.Reader) (*bls12381.PointG1, *gnark.G1Affine, error) { panic("bytes(gnark.G1) != bytes(geth.G1)") } - return kp, cp, nil + // marshal gnark point -> blst point + var p1 *blst.P1Affine + var scalar *blst.Scalar + scalar.Deserialize(s.Bytes()) + p1.From(scalar) + if !bytes.Equal(p1.Serialize(), cpBytes) { + panic("bytes(blst.G1) != bytes(geth.G1)") + } + + return kp, cp, p1, nil } -func getG2Points(input io.Reader) (*bls12381.PointG2, *gnark.G2Affine, error) { +func getG2Points(input io.Reader) (*bls12381.PointG2, *gnark.G2Affine, *blst.P2Affine, error) { // sample a random scalar s, err := randomScalar(input, fp.Modulus()) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // compute a random point @@ -232,7 +261,16 @@ func getG2Points(input io.Reader) (*bls12381.PointG2, *gnark.G2Affine, error) { panic("bytes(gnark.G2) != bytes(geth.G2)") } - return kp, cp, nil + // marshal gnark point -> blst point + var p2 *blst.P2Affine + var scalar *blst.Scalar + scalar.Deserialize(s.Bytes()) + p2.From(scalar) + if !bytes.Equal(p2.Serialize(), cpBytes) { + panic("bytes(blst.G2) != bytes(geth.G2)") + } + + return kp, cp, p2, nil } func randomScalar(r io.Reader, max *big.Int) (k *big.Int, err error) {