From cc87cbd70af18241f79908eec10bb3c51a9fbda4 Mon Sep 17 00:00:00 2001 From: Fredrik Svantes Date: Mon, 6 Dec 2021 13:46:19 +0100 Subject: [PATCH 01/12] security policy: updated pgp key (#24069) --- SECURITY.md | 229 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 142 insertions(+), 87 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 635c0869fc..88b3f8fe17 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -29,92 +29,147 @@ Fingerprint: `AE96 ED96 9E47 9B00 84F3 E17F E88D 3334 FA5F 6A0A` ``` -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 +Version: SKS 1.1.6 +Comment: Hostname: pgp.mit.edu -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 -=r6KK ------END PGP PUBLIC KEY BLOCK----- +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 +=arte +-----END PGP PUBLIC KEY BLOCK------ ``` From d78590560d0107e727a44d0eea088eeb4d280bab Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Mon, 6 Dec 2021 20:36:01 -0500 Subject: [PATCH 02/12] eth/filters: remove unused field 'chaindb' in PublicFilterAPI (#24072) --- eth/filters/api.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index e0b07e318e..6b28ec9610 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/rpc" ) @@ -51,7 +50,6 @@ type PublicFilterAPI struct { backend Backend mux *event.TypeMux quit chan struct{} - chainDb ethdb.Database events *EventSystem filtersMu sync.Mutex filters map[rpc.ID]*filter @@ -62,7 +60,6 @@ type PublicFilterAPI struct { func NewPublicFilterAPI(backend Backend, lightMode bool, timeout time.Duration) *PublicFilterAPI { api := &PublicFilterAPI{ backend: backend, - chainDb: backend.ChainDb(), events: NewEventSystem(backend, lightMode), filters: make(map[rpc.ID]*filter), timeout: timeout, From 7f7877a02326ecace5c120ddced413880c272170 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 7 Dec 2021 17:42:09 +0800 Subject: [PATCH 03/12] miner: update pending block even after the PoS transition (#24075) --- miner/worker.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 041c03af80..2c576ad082 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1039,17 +1039,15 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st if err != nil { return err } - - // If we're post merge, just ignore - td, ttd := w.chain.GetTd(block.ParentHash(), block.NumberU64()-1), w.chain.Config().TerminalTotalDifficulty - if td != nil && ttd != nil && td.Cmp(ttd) >= 0 { - return nil - } - if w.isRunning() { if interval != nil { interval() } + // If we're post merge, just ignore + td, ttd := w.chain.GetTd(block.ParentHash(), block.NumberU64()-1), w.chain.Config().TerminalTotalDifficulty + if td != nil && ttd != nil && td.Cmp(ttd) >= 0 { + return nil + } select { case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: w.unconfirmed.Shift(block.NumberU64() - 1) From db03faa10d402bcc70054aa2d3e70eecc37a57e2 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 7 Dec 2021 17:50:58 +0100 Subject: [PATCH 04/12] core, eth: improve delivery speed on header requests (#23105) This PR reduces the amount of work we do when answering header queries, e.g. when a peer is syncing from us. For some items, e.g block bodies, when we read the rlp-data from database, we plug it directly into the response package. We didn't do that for headers, but instead read headers-rlp, decode to types.Header, and re-encode to rlp. This PR changes that to keep it in RLP-form as much as possible. When a node is syncing from us, it typically requests 192 contiguous headers. On master it has the following effect: - For headers not in ancient: 2 db lookups. One for translating hash->number (even though the request is by number), and another for reading by hash (this latter one is sometimes cached). - For headers in ancient: 1 file lookup/syscall for translating hash->number (even though the request is by number), and another for reading the header itself. After this, it also performes a hashing of the header, to ensure that the hash is what it expected. In this PR, I instead move the logic for "give me a sequence of blocks" into the lower layers, where the database can determine how and what to read from leveldb and/or ancients. There are basically four types of requests; three of them are improved this way. The fourth, by hash going backwards, is more tricky to optimize. However, since we know that the gap is 0, we can look up by the parentHash, and stlil shave off all the number->hash lookups. The gapped collection can be optimized similarly, as a follow-up, at least in three out of four cases. Co-authored-by: Felix Lange --- core/blockchain_reader.go | 6 +++ core/headerchain.go | 41 ++++++++++++++ core/rawdb/accessors_chain.go | 50 +++++++++++++++++ core/rawdb/accessors_chain_test.go | 64 ++++++++++++++++++++++ core/types/block.go | 18 +++++++ core/types/block_test.go | 61 +++++++++++++++++++++ eth/downloader/downloader_test.go | 20 +++++-- eth/handler_eth_test.go | 9 ++-- eth/protocols/eth/handler.go | 3 -- eth/protocols/eth/handler_test.go | 15 ++++-- eth/protocols/eth/handlers.go | 87 +++++++++++++++++++++++++++--- eth/protocols/eth/peer.go | 8 +-- eth/protocols/eth/protocol.go | 10 ++++ 13 files changed, 368 insertions(+), 24 deletions(-) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index beaa57b0c1..9e966df4e0 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -73,6 +73,12 @@ func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header { return bc.hc.GetHeaderByNumber(number) } +// GetHeadersFrom returns a contiguous segment of headers, in rlp-form, going +// backwards from the given number. +func (bc *BlockChain) GetHeadersFrom(number, count uint64) []rlp.RawValue { + return bc.hc.GetHeadersFrom(number, count) +} + // GetBody retrieves a block body (transactions and uncles) from the database by // hash, caching it if found. func (bc *BlockChain) GetBody(hash common.Hash) *types.Body { diff --git a/core/headerchain.go b/core/headerchain.go index 335945d48f..99364f638f 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" lru "github.com/hashicorp/golang-lru" ) @@ -498,6 +499,46 @@ func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { return hc.GetHeader(hash, number) } +// GetHeadersFrom returns a contiguous segment of headers, in rlp-form, going +// backwards from the given number. +// If the 'number' is higher than the highest local header, this method will +// return a best-effort response, containing the headers that we do have. +func (hc *HeaderChain) GetHeadersFrom(number, count uint64) []rlp.RawValue { + // If the request is for future headers, we still return the portion of + // headers that we are able to serve + if current := hc.CurrentHeader().Number.Uint64(); current < number { + if count > number-current { + count -= number - current + number = current + } else { + return nil + } + } + var headers []rlp.RawValue + // If we have some of the headers in cache already, use that before going to db. + hash := rawdb.ReadCanonicalHash(hc.chainDb, number) + if hash == (common.Hash{}) { + return nil + } + for count > 0 { + header, ok := hc.headerCache.Get(hash) + if !ok { + break + } + h := header.(*types.Header) + rlpData, _ := rlp.EncodeToBytes(h) + headers = append(headers, rlpData) + hash = h.ParentHash + count-- + number-- + } + // Read remaining from db + if count > 0 { + headers = append(headers, rawdb.ReadHeaderRange(hc.chainDb, number, count)...) + } + return headers +} + func (hc *HeaderChain) GetCanonicalHash(number uint64) common.Hash { return rawdb.ReadCanonicalHash(hc.chainDb, number) } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 82d3f5c0c6..7f46f9d72b 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -279,6 +279,56 @@ func WriteFastTxLookupLimit(db ethdb.KeyValueWriter, number uint64) { } } +// ReadHeaderRange returns the rlp-encoded headers, starting at 'number', and going +// backwards towards genesis. This method assumes that the caller already has +// placed a cap on count, to prevent DoS issues. +// Since this method operates in head-towards-genesis mode, it will return an empty +// slice in case the head ('number') is missing. Hence, the caller must ensure that +// the head ('number') argument is actually an existing header. +// +// N.B: Since the input is a number, as opposed to a hash, it's implicit that +// this method only operates on canon headers. +func ReadHeaderRange(db ethdb.Reader, number uint64, count uint64) []rlp.RawValue { + var rlpHeaders []rlp.RawValue + if count == 0 { + return rlpHeaders + } + i := number + if count-1 > number { + // It's ok to request block 0, 1 item + count = number + 1 + } + limit, _ := db.Ancients() + // First read live blocks + if i >= limit { + // If we need to read live blocks, we need to figure out the hash first + hash := ReadCanonicalHash(db, number) + for ; i >= limit && count > 0; i-- { + if data, _ := db.Get(headerKey(i, hash)); len(data) > 0 { + rlpHeaders = append(rlpHeaders, data) + // Get the parent hash for next query + hash = types.HeaderParentHashFromRLP(data) + } else { + break // Maybe got moved to ancients + } + count-- + } + } + if count == 0 { + return rlpHeaders + } + // read remaining from ancients + max := count * 700 + data, err := db.AncientRange(freezerHeaderTable, i+1-count, count, max) + if err == nil && uint64(len(data)) == count { + // the data is on the order [h, h+1, .., n] -- reordering needed + for i := range data { + rlpHeaders = append(rlpHeaders, data[len(data)-1-i]) + } + } + return rlpHeaders +} + // ReadHeaderRLP retrieves a block header in its raw RLP database encoding. func ReadHeaderRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { var data []byte diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 50b0d53902..2c36de8980 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -883,3 +883,67 @@ func BenchmarkDecodeRLPLogs(b *testing.B) { } }) } + +func TestHeadersRLPStorage(t *testing.T) { + // Have N headers in the freezer + frdir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("failed to create temp freezer dir: %v", err) + } + defer os.Remove(frdir) + + db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false) + if err != nil { + t.Fatalf("failed to create database with ancient backend") + } + defer db.Close() + // Create blocks + var chain []*types.Block + var pHash common.Hash + for i := 0; i < 100; i++ { + block := types.NewBlockWithHeader(&types.Header{ + Number: big.NewInt(int64(i)), + Extra: []byte("test block"), + UncleHash: types.EmptyUncleHash, + TxHash: types.EmptyRootHash, + ReceiptHash: types.EmptyRootHash, + ParentHash: pHash, + }) + chain = append(chain, block) + pHash = block.Hash() + } + var receipts []types.Receipts = make([]types.Receipts, 100) + // Write first half to ancients + WriteAncientBlocks(db, chain[:50], receipts[:50], big.NewInt(100)) + // Write second half to db + for i := 50; i < 100; i++ { + WriteCanonicalHash(db, chain[i].Hash(), chain[i].NumberU64()) + WriteBlock(db, chain[i]) + } + checkSequence := func(from, amount int) { + headersRlp := ReadHeaderRange(db, uint64(from), uint64(amount)) + if have, want := len(headersRlp), amount; have != want { + t.Fatalf("have %d headers, want %d", have, want) + } + for i, headerRlp := range headersRlp { + var header types.Header + if err := rlp.DecodeBytes(headerRlp, &header); err != nil { + t.Fatal(err) + } + if have, want := header.Number.Uint64(), uint64(from-i); have != want { + t.Fatalf("wrong number, have %d want %d", have, want) + } + } + } + checkSequence(99, 20) // Latest block and 19 parents + checkSequence(99, 50) // Latest block -> all db blocks + checkSequence(99, 51) // Latest block -> one from ancients + checkSequence(99, 52) // Latest blocks -> two from ancients + checkSequence(50, 2) // One from db, one from ancients + checkSequence(49, 1) // One from ancients + checkSequence(49, 50) // All ancient ones + checkSequence(99, 100) // All blocks + checkSequence(0, 1) // Only genesis + checkSequence(1, 1) // Only block 1 + checkSequence(1, 2) // Genesis + block 1 +} diff --git a/core/types/block.go b/core/types/block.go index 92e5cb7727..f38c55c1ff 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -389,3 +389,21 @@ func (b *Block) Hash() common.Hash { } type Blocks []*Block + +// HeaderParentHashFromRLP returns the parentHash of an RLP-encoded +// header. If 'header' is invalid, the zero hash is returned. +func HeaderParentHashFromRLP(header []byte) common.Hash { + // parentHash is the first list element. + listContent, _, err := rlp.SplitList(header) + if err != nil { + return common.Hash{} + } + parentHash, _, err := rlp.SplitString(listContent) + if err != nil { + return common.Hash{} + } + if len(parentHash) != 32 { + return common.Hash{} + } + return common.BytesToHash(parentHash) +} diff --git a/core/types/block_test.go b/core/types/block_test.go index 0b9a4def8d..5cdea3fc06 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -281,3 +281,64 @@ func makeBenchBlock() *Block { } return NewBlock(header, txs, uncles, receipts, newHasher()) } + +func TestRlpDecodeParentHash(t *testing.T) { + // A minimum one + want := common.HexToHash("0x112233445566778899001122334455667788990011223344556677889900aabb") + if rlpData, err := rlp.EncodeToBytes(Header{ParentHash: want}); err != nil { + t.Fatal(err) + } else { + if have := HeaderParentHashFromRLP(rlpData); have != want { + t.Fatalf("have %x, want %x", have, want) + } + } + // And a maximum one + // | Difficulty | dynamic| *big.Int | 0x5ad3c2c71bbff854908 (current mainnet TD: 76 bits) | + // | Number | dynamic| *big.Int | 64 bits | + // | Extra | dynamic| []byte | 65+32 byte (clique) | + // | BaseFee | dynamic| *big.Int | 64 bits | + mainnetTd := new(big.Int) + mainnetTd.SetString("5ad3c2c71bbff854908", 16) + if rlpData, err := rlp.EncodeToBytes(Header{ + ParentHash: want, + Difficulty: mainnetTd, + Number: new(big.Int).SetUint64(math.MaxUint64), + Extra: make([]byte, 65+32), + BaseFee: new(big.Int).SetUint64(math.MaxUint64), + }); err != nil { + t.Fatal(err) + } else { + if have := HeaderParentHashFromRLP(rlpData); have != want { + t.Fatalf("have %x, want %x", have, want) + } + } + // Also test a very very large header. + { + // The rlp-encoding of the heder belowCauses _total_ length of 65540, + // which is the first to blow the fast-path. + h := Header{ + ParentHash: want, + Extra: make([]byte, 65041), + } + if rlpData, err := rlp.EncodeToBytes(h); err != nil { + t.Fatal(err) + } else { + if have := HeaderParentHashFromRLP(rlpData); have != want { + t.Fatalf("have %x, want %x", have, want) + } + } + } + { + // Test some invalid erroneous stuff + for i, rlpData := range [][]byte{ + nil, + common.FromHex("0x"), + common.FromHex("0x01"), + common.FromHex("0x3031323334"), + } { + if have, want := HeaderParentHashFromRLP(rlpData), (common.Hash{}); have != want { + t.Fatalf("invalid %d: have %x, want %x", i, have, want) + } + } + } +} diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 3e78a0bb7f..70c6a51215 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -154,12 +154,24 @@ func (dlp *downloadTesterPeer) Head() (common.Hash, *big.Int) { return head.Hash(), dlp.chain.GetTd(head.Hash(), head.NumberU64()) } +func unmarshalRlpHeaders(rlpdata []rlp.RawValue) []*types.Header { + var headers = make([]*types.Header, len(rlpdata)) + for i, data := range rlpdata { + var h types.Header + if err := rlp.DecodeBytes(data, &h); err != nil { + panic(err) + } + headers[i] = &h + } + return headers +} + // RequestHeadersByHash constructs a GetBlockHeaders function based on a hashed // origin; associated with a particular peer in the download tester. The returned // function can be used to retrieve batches of headers from the particular peer. func (dlp *downloadTesterPeer) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool, sink chan *eth.Response) (*eth.Request, error) { // Service the header query via the live handler code - headers := eth.ServiceGetBlockHeadersQuery(dlp.chain, ð.GetBlockHeadersPacket{ + rlpHeaders := eth.ServiceGetBlockHeadersQuery(dlp.chain, ð.GetBlockHeadersPacket{ Origin: eth.HashOrNumber{ Hash: origin, }, @@ -167,7 +179,7 @@ func (dlp *downloadTesterPeer) RequestHeadersByHash(origin common.Hash, amount i Skip: uint64(skip), Reverse: reverse, }, nil) - + headers := unmarshalRlpHeaders(rlpHeaders) // If a malicious peer is simulated withholding headers, delete them for hash := range dlp.withholdHeaders { for i, header := range headers { @@ -203,7 +215,7 @@ func (dlp *downloadTesterPeer) RequestHeadersByHash(origin common.Hash, amount i // function can be used to retrieve batches of headers from the particular peer. func (dlp *downloadTesterPeer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool, sink chan *eth.Response) (*eth.Request, error) { // Service the header query via the live handler code - headers := eth.ServiceGetBlockHeadersQuery(dlp.chain, ð.GetBlockHeadersPacket{ + rlpHeaders := eth.ServiceGetBlockHeadersQuery(dlp.chain, ð.GetBlockHeadersPacket{ Origin: eth.HashOrNumber{ Number: origin, }, @@ -211,7 +223,7 @@ func (dlp *downloadTesterPeer) RequestHeadersByNumber(origin uint64, amount int, Skip: uint64(skip), Reverse: reverse, }, nil) - + headers := unmarshalRlpHeaders(rlpHeaders) // If a malicious peer is simulated withholding headers, delete them for hash := range dlp.withholdHeaders { for i, header := range headers { diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index b826ed7a9d..6e1c57cb6c 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" ) // testEthHandler is a mock event handler to listen for inbound network requests @@ -560,15 +561,17 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo // Create a block to reply to the challenge if no timeout is simulated. if !timeout { if empty { - if err := remote.ReplyBlockHeaders(request.RequestId, []*types.Header{}); err != nil { + if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{}); err != nil { t.Fatalf("failed to answer challenge: %v", err) } } else if match { - if err := remote.ReplyBlockHeaders(request.RequestId, []*types.Header{response}); err != nil { + responseRlp, _ := rlp.EncodeToBytes(response) + if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{responseRlp}); err != nil { t.Fatalf("failed to answer challenge: %v", err) } } else { - if err := remote.ReplyBlockHeaders(request.RequestId, []*types.Header{{Number: response.Number}}); err != nil { + responseRlp, _ := rlp.EncodeToBytes(types.Header{Number: response.Number}) + if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{responseRlp}); err != nil { t.Fatalf("failed to answer challenge: %v", err) } } diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 6e0fc4a373..81d45d8b8f 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -35,9 +35,6 @@ const ( // softResponseLimit is the target maximum size of replies to data retrievals. softResponseLimit = 2 * 1024 * 1024 - // estHeaderSize is the approximate size of an RLP encoded block header. - estHeaderSize = 500 - // maxHeadersServe is the maximum number of block headers to serve. This number // is there to limit the number of disk lookups. maxHeadersServe = 1024 diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 5192f043dd..7d9b378839 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -136,11 +136,13 @@ func testGetBlockHeaders(t *testing.T, protocol uint) { query *GetBlockHeadersPacket // The query to execute for header retrieval expect []common.Hash // The hashes of the block whose headers are expected }{ - // A single random block should be retrievable by hash and number too + // A single random block should be retrievable by hash { &GetBlockHeadersPacket{Origin: HashOrNumber{Hash: backend.chain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1}, []common.Hash{backend.chain.GetBlockByNumber(limit / 2).Hash()}, - }, { + }, + // A single random block should be retrievable by number + { &GetBlockHeadersPacket{Origin: HashOrNumber{Number: limit / 2}, Amount: 1}, []common.Hash{backend.chain.GetBlockByNumber(limit / 2).Hash()}, }, @@ -180,10 +182,15 @@ func testGetBlockHeaders(t *testing.T, protocol uint) { { &GetBlockHeadersPacket{Origin: HashOrNumber{Number: 0}, Amount: 1}, []common.Hash{backend.chain.GetBlockByNumber(0).Hash()}, - }, { + }, + { &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64()}, Amount: 1}, []common.Hash{backend.chain.CurrentBlock().Hash()}, }, + { // If the peer requests a bit into the future, we deliver what we have + &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64()}, Amount: 10}, + []common.Hash{backend.chain.CurrentBlock().Hash()}, + }, // Ensure protocol limits are honored { &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true}, @@ -280,7 +287,7 @@ func testGetBlockHeaders(t *testing.T, protocol uint) { RequestId: 456, BlockHeadersPacket: headers, }); err != nil { - t.Errorf("test %d: headers mismatch: %v", i, err) + t.Errorf("test %d by hash: headers mismatch: %v", i, err) } } } diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 503e572a83..8fc966e7ae 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -36,12 +36,21 @@ func handleGetBlockHeaders66(backend Backend, msg Decoder, peer *Peer) error { return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) } response := ServiceGetBlockHeadersQuery(backend.Chain(), query.GetBlockHeadersPacket, peer) - return peer.ReplyBlockHeaders(query.RequestId, response) + return peer.ReplyBlockHeadersRLP(query.RequestId, response) } // ServiceGetBlockHeadersQuery assembles the response to a header query. It is // exposed to allow external packages to test protocol behavior. -func ServiceGetBlockHeadersQuery(chain *core.BlockChain, query *GetBlockHeadersPacket, peer *Peer) []*types.Header { +func ServiceGetBlockHeadersQuery(chain *core.BlockChain, query *GetBlockHeadersPacket, peer *Peer) []rlp.RawValue { + if query.Skip == 0 { + // The fast path: when the request is for a contiguous segment of headers. + return serviceContiguousBlockHeaderQuery(chain, query) + } else { + return serviceNonContiguousBlockHeaderQuery(chain, query, peer) + } +} + +func serviceNonContiguousBlockHeaderQuery(chain *core.BlockChain, query *GetBlockHeadersPacket, peer *Peer) []rlp.RawValue { hashMode := query.Origin.Hash != (common.Hash{}) first := true maxNonCanonical := uint64(100) @@ -49,7 +58,7 @@ func ServiceGetBlockHeadersQuery(chain *core.BlockChain, query *GetBlockHeadersP // Gather headers until the fetch or network limits is reached var ( bytes common.StorageSize - headers []*types.Header + headers []rlp.RawValue unknown bool lookups int ) @@ -74,9 +83,12 @@ func ServiceGetBlockHeadersQuery(chain *core.BlockChain, query *GetBlockHeadersP if origin == nil { break } - headers = append(headers, origin) - bytes += estHeaderSize - + if rlpData, err := rlp.EncodeToBytes(origin); err != nil { + log.Crit("Unable to decode our own headers", "err", err) + } else { + headers = append(headers, rlp.RawValue(rlpData)) + bytes += common.StorageSize(len(rlpData)) + } // Advance to the next header of the query switch { case hashMode && query.Reverse: @@ -127,6 +139,69 @@ func ServiceGetBlockHeadersQuery(chain *core.BlockChain, query *GetBlockHeadersP return headers } +func serviceContiguousBlockHeaderQuery(chain *core.BlockChain, query *GetBlockHeadersPacket) []rlp.RawValue { + count := query.Amount + if count > maxHeadersServe { + count = maxHeadersServe + } + if query.Origin.Hash == (common.Hash{}) { + // Number mode, just return the canon chain segment. The backend + // delivers in [N, N-1, N-2..] descending order, so we need to + // accommodate for that. + from := query.Origin.Number + if !query.Reverse { + from = from + count - 1 + } + headers := chain.GetHeadersFrom(from, count) + if !query.Reverse { + for i, j := 0, len(headers)-1; i < j; i, j = i+1, j-1 { + headers[i], headers[j] = headers[j], headers[i] + } + } + return headers + } + // Hash mode. + var ( + headers []rlp.RawValue + hash = query.Origin.Hash + header = chain.GetHeaderByHash(hash) + ) + if header != nil { + rlpData, _ := rlp.EncodeToBytes(header) + headers = append(headers, rlpData) + } else { + // We don't even have the origin header + return headers + } + num := header.Number.Uint64() + if !query.Reverse { + // Theoretically, we are tasked to deliver header by hash H, and onwards. + // However, if H is not canon, we will be unable to deliver any descendants of + // H. + if canonHash := chain.GetCanonicalHash(num); canonHash != hash { + // Not canon, we can't deliver descendants + return headers + } + descendants := chain.GetHeadersFrom(num+count-1, count-1) + for i, j := 0, len(descendants)-1; i < j; i, j = i+1, j-1 { + descendants[i], descendants[j] = descendants[j], descendants[i] + } + headers = append(headers, descendants...) + return headers + } + { // Last mode: deliver ancestors of H + for i := uint64(1); header != nil && i < count; i++ { + header = chain.GetHeaderByHash(header.ParentHash) + if header == nil { + break + } + rlpData, _ := rlp.EncodeToBytes(header) + headers = append(headers, rlpData) + } + return headers + } +} + func handleGetBlockBodies66(backend Backend, msg Decoder, peer *Peer) error { // Decode the block body retrieval message var query GetBlockBodiesPacket66 diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index b61dc25af6..4161420f3a 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -297,10 +297,10 @@ func (p *Peer) AsyncSendNewBlock(block *types.Block, td *big.Int) { } // ReplyBlockHeaders is the eth/66 version of SendBlockHeaders. -func (p *Peer) ReplyBlockHeaders(id uint64, headers []*types.Header) error { - return p2p.Send(p.rw, BlockHeadersMsg, BlockHeadersPacket66{ - RequestId: id, - BlockHeadersPacket: headers, +func (p *Peer) ReplyBlockHeadersRLP(id uint64, headers []rlp.RawValue) error { + return p2p.Send(p.rw, BlockHeadersMsg, BlockHeadersRLPPacket66{ + RequestId: id, + BlockHeadersRLPPacket: headers, }) } diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index 3c3da30fa5..a8420ad68c 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -175,6 +175,16 @@ type BlockHeadersPacket66 struct { BlockHeadersPacket } +// BlockHeadersRLPPacket represents a block header response, to use when we already +// have the headers rlp encoded. +type BlockHeadersRLPPacket []rlp.RawValue + +// BlockHeadersPacket represents a block header response over eth/66. +type BlockHeadersRLPPacket66 struct { + RequestId uint64 + BlockHeadersRLPPacket +} + // NewBlockPacket is the network packet for the block propagation message. type NewBlockPacket struct { Block *types.Block From ae8ff2661d917506ec29bd8f457884d483e2ce42 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 9 Dec 2021 12:55:06 +0000 Subject: [PATCH 05/12] core/vm: remove unused code (IsStaticJump) (#24085) --- core/vm/opcodes.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index b02d13eacc..2b4cc3375f 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -32,11 +32,6 @@ func (op OpCode) IsPush() bool { return false } -// IsStaticJump specifies if an opcode is JUMP. -func (op OpCode) IsStaticJump() bool { - return op == JUMP -} - // 0x0 range - arithmetic ops. const ( STOP OpCode = 0x0 From 72c2c0ae7e2332b08d3e1ebfe5f850a92e26e8a1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 11 Dec 2021 16:51:05 +0100 Subject: [PATCH 06/12] cmd/geth, console: support interrupting the js console (#23387) Previously, Ctrl-C (SIGINT) was ignored during JS execution, so it was not possible to get out of infinite loops in the console. With this change, Ctrl-C now interrupts JS. Fixes #23344 Co-authored-by: Sina Mahmoodi Co-authored-by: Felix Lange --- cmd/geth/consolecmd.go | 49 ++++++++-------- cmd/geth/main.go | 6 +- cmd/utils/cmd.go | 36 ++++++++---- console/console.go | 123 ++++++++++++++++++++++++++++++++++------- internal/jsre/jsre.go | 42 +++++++++++--- 5 files changed, 193 insertions(+), 63 deletions(-) diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 8a767241e9..7a0135b9a1 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -77,13 +77,13 @@ func localConsole(ctx *cli.Context) error { // Create and start the node based on the CLI flags prepare(ctx) stack, backend := makeFullNode(ctx) - startNode(ctx, stack, backend) + startNode(ctx, stack, backend, true) defer stack.Close() - // Attach to the newly started node and start the JavaScript console + // Attach to the newly started node and create the JavaScript console. client, err := stack.Attach() if err != nil { - utils.Fatalf("Failed to attach to the inproc geth: %v", err) + return fmt.Errorf("Failed to attach to the inproc geth: %v", err) } config := console.Config{ DataDir: utils.MakeDataDir(ctx), @@ -91,29 +91,34 @@ func localConsole(ctx *cli.Context) error { Client: client, Preload: utils.MakeConsolePreloads(ctx), } - console, err := console.New(config) if err != nil { - utils.Fatalf("Failed to start the JavaScript console: %v", err) + return fmt.Errorf("Failed to start the JavaScript console: %v", err) } defer console.Stop(false) - // If only a short execution was requested, evaluate and return + // If only a short execution was requested, evaluate and return. if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { console.Evaluate(script) return nil } - // Otherwise print the welcome screen and enter interactive mode + + // Track node shutdown and stop the console when it goes down. + // This happens when SIGTERM is sent to the process. + go func() { + stack.Wait() + console.StopInteractive() + }() + + // Print the welcome screen and enter interactive mode. console.Welcome() console.Interactive() - return nil } // remoteConsole will connect to a remote geth instance, attaching a JavaScript // console to it. func remoteConsole(ctx *cli.Context) error { - // Attach to a remotely running geth instance and start the JavaScript console endpoint := ctx.Args().First() if endpoint == "" { path := node.DefaultDataDir() @@ -150,7 +155,6 @@ func remoteConsole(ctx *cli.Context) error { Client: client, Preload: utils.MakeConsolePreloads(ctx), } - console, err := console.New(config) if err != nil { utils.Fatalf("Failed to start the JavaScript console: %v", err) @@ -165,7 +169,6 @@ func remoteConsole(ctx *cli.Context) error { // Otherwise print the welcome screen and enter interactive mode console.Welcome() console.Interactive() - return nil } @@ -189,13 +192,13 @@ func dialRPC(endpoint string) (*rpc.Client, error) { func ephemeralConsole(ctx *cli.Context) error { // Create and start the node based on the CLI flags stack, backend := makeFullNode(ctx) - startNode(ctx, stack, backend) + startNode(ctx, stack, backend, false) defer stack.Close() // Attach to the newly started node and start the JavaScript console client, err := stack.Attach() if err != nil { - utils.Fatalf("Failed to attach to the inproc geth: %v", err) + return fmt.Errorf("Failed to attach to the inproc geth: %v", err) } config := console.Config{ DataDir: utils.MakeDataDir(ctx), @@ -206,22 +209,24 @@ func ephemeralConsole(ctx *cli.Context) error { console, err := console.New(config) if err != nil { - utils.Fatalf("Failed to start the JavaScript console: %v", err) + return fmt.Errorf("Failed to start the JavaScript console: %v", err) } defer console.Stop(false) - // Evaluate each of the specified JavaScript files - for _, file := range ctx.Args() { - if err = console.Execute(file); err != nil { - utils.Fatalf("Failed to execute %s: %v", file, err) - } - } - + // Interrupt the JS interpreter when node is stopped. go func() { stack.Wait() console.Stop(false) }() - console.Stop(true) + // Evaluate each of the specified JavaScript files. + for _, file := range ctx.Args() { + if err = console.Execute(file); err != nil { + return fmt.Errorf("Failed to execute %s: %v", file, err) + } + } + + // The main script is now done, but keep running timers/callbacks. + console.Stop(true) return nil } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 07e870a3b0..c82fe8265b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -320,7 +320,7 @@ func geth(ctx *cli.Context) error { stack, backend := makeFullNode(ctx) defer stack.Close() - startNode(ctx, stack, backend) + startNode(ctx, stack, backend, false) stack.Wait() return nil } @@ -328,11 +328,11 @@ func geth(ctx *cli.Context) error { // startNode boots up the system node and all registered protocols, after which // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // miner. -func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) { +func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isConsole bool) { debug.Memsize.Add("node", stack) // Start up the node itself - utils.StartNode(ctx, stack) + utils.StartNode(ctx, stack, isConsole) // Unlock any account specifically requested unlockAccounts(ctx, stack) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index ddd8d822b3..f8e40b187c 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -68,7 +68,7 @@ func Fatalf(format string, args ...interface{}) { os.Exit(1) } -func StartNode(ctx *cli.Context, stack *node.Node) { +func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { if err := stack.Start(); err != nil { Fatalf("Error starting protocol stack: %v", err) } @@ -87,17 +87,33 @@ func StartNode(ctx *cli.Context, stack *node.Node) { go monitorFreeDiskSpace(sigc, stack.InstanceDir(), uint64(minFreeDiskSpace)*1024*1024) } - <-sigc - log.Info("Got interrupt, shutting down...") - go stack.Close() - for i := 10; i > 0; i-- { - <-sigc - if i > 1 { - log.Warn("Already shutting down, interrupt more to panic.", "times", i-1) + shutdown := func() { + log.Info("Got interrupt, shutting down...") + go stack.Close() + for i := 10; i > 0; i-- { + <-sigc + if i > 1 { + log.Warn("Already shutting down, interrupt more to panic.", "times", i-1) + } } + debug.Exit() // ensure trace and CPU profile data is flushed. + debug.LoudPanic("boom") + } + + if isConsole { + // In JS console mode, SIGINT is ignored because it's handled by the console. + // However, SIGTERM still shuts down the node. + for { + sig := <-sigc + if sig == syscall.SIGTERM { + shutdown() + return + } + } + } else { + <-sigc + shutdown() } - debug.Exit() // ensure trace and CPU profile data is flushed. - debug.LoudPanic("boom") }() } diff --git a/console/console.go b/console/console.go index dd39300d0a..ab26bd64f7 100644 --- a/console/console.go +++ b/console/console.go @@ -17,6 +17,7 @@ package console import ( + "errors" "fmt" "io" "io/ioutil" @@ -26,6 +27,7 @@ import ( "regexp" "sort" "strings" + "sync" "syscall" "github.com/dop251/goja" @@ -74,6 +76,13 @@ type Console struct { histPath string // Absolute path to the console scrollback history history []string // Scroll history maintained by the console printer io.Writer // Output writer to serialize any display strings to + + interactiveStopped chan struct{} + stopInteractiveCh chan struct{} + signalReceived chan struct{} + stopped chan struct{} + wg sync.WaitGroup + stopOnce sync.Once } // New initializes a JavaScript interpreted runtime environment and sets defaults @@ -92,12 +101,16 @@ func New(config Config) (*Console, error) { // Initialize the console and return console := &Console{ - client: config.Client, - jsre: jsre.New(config.DocRoot, config.Printer), - prompt: config.Prompt, - prompter: config.Prompter, - printer: config.Printer, - histPath: filepath.Join(config.DataDir, HistoryFile), + client: config.Client, + jsre: jsre.New(config.DocRoot, config.Printer), + prompt: config.Prompt, + prompter: config.Prompter, + printer: config.Printer, + histPath: filepath.Join(config.DataDir, HistoryFile), + interactiveStopped: make(chan struct{}), + stopInteractiveCh: make(chan struct{}), + signalReceived: make(chan struct{}, 1), + stopped: make(chan struct{}), } if err := os.MkdirAll(config.DataDir, 0700); err != nil { return nil, err @@ -105,6 +118,10 @@ func New(config Config) (*Console, error) { if err := console.init(config.Preload); err != nil { return nil, err } + + console.wg.Add(1) + go console.interruptHandler() + return console, nil } @@ -337,9 +354,63 @@ func (c *Console) Evaluate(statement string) { } }() c.jsre.Evaluate(statement, c.printer) + + // Avoid exiting Interactive when jsre was interrupted by SIGINT. + c.clearSignalReceived() } -// Interactive starts an interactive user session, where input is propted from +// interruptHandler runs in its own goroutine and waits for signals. +// When a signal is received, it interrupts the JS interpreter. +func (c *Console) interruptHandler() { + defer c.wg.Done() + + // During Interactive, liner inhibits the signal while it is prompting for + // input. However, the signal will be received while evaluating JS. + // + // On unsupported terminals, SIGINT can also happen while prompting. + // Unfortunately, it is not possible to abort the prompt in this case and + // the c.readLines goroutine leaks. + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGINT) + defer signal.Stop(sig) + + for { + select { + case <-sig: + c.setSignalReceived() + c.jsre.Interrupt(errors.New("interrupted")) + case <-c.stopInteractiveCh: + close(c.interactiveStopped) + c.jsre.Interrupt(errors.New("interrupted")) + case <-c.stopped: + return + } + } +} + +func (c *Console) setSignalReceived() { + select { + case c.signalReceived <- struct{}{}: + default: + } +} + +func (c *Console) clearSignalReceived() { + select { + case <-c.signalReceived: + default: + } +} + +// StopInteractive causes Interactive to return as soon as possible. +func (c *Console) StopInteractive() { + select { + case c.stopInteractiveCh <- struct{}{}: + case <-c.stopped: + } +} + +// Interactive starts an interactive user session, where in.put is propted from // the configured user prompter. func (c *Console) Interactive() { var ( @@ -349,15 +420,11 @@ func (c *Console) Interactive() { inputLine = make(chan string, 1) // receives user input inputErr = make(chan error, 1) // receives liner errors requestLine = make(chan string) // requests a line of input - interrupt = make(chan os.Signal, 1) ) - // Monitor Ctrl-C. While liner does turn on the relevant terminal mode bits to avoid - // the signal, a signal can still be received for unsupported terminals. Unfortunately - // there is no way to cancel the line reader when this happens. The readLines - // goroutine will be leaked in this case. - signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) - defer signal.Stop(interrupt) + defer func() { + c.writeHistory() + }() // The line reader runs in a separate goroutine. go c.readLines(inputLine, inputErr, requestLine) @@ -368,7 +435,14 @@ func (c *Console) Interactive() { requestLine <- prompt select { - case <-interrupt: + case <-c.interactiveStopped: + fmt.Fprintln(c.printer, "node is down, exiting console") + return + + case <-c.signalReceived: + // SIGINT received while prompting for input -> unsupported terminal. + // I'm not sure if the best choice would be to leave the console running here. + // Bash keeps running in this case. node.js does not. fmt.Fprintln(c.printer, "caught interrupt, exiting") return @@ -476,12 +550,19 @@ func (c *Console) Execute(path string) error { // Stop cleans up the console and terminates the runtime environment. func (c *Console) Stop(graceful bool) error { - if err := ioutil.WriteFile(c.histPath, []byte(strings.Join(c.history, "\n")), 0600); err != nil { - return err - } - if err := os.Chmod(c.histPath, 0600); err != nil { // Force 0600, even if it was different previously - return err - } + c.stopOnce.Do(func() { + // Stop the interrupt handler. + close(c.stopped) + c.wg.Wait() + }) + c.jsre.Stop(graceful) return nil } + +func (c *Console) writeHistory() error { + if err := ioutil.WriteFile(c.histPath, []byte(strings.Join(c.history, "\n")), 0600); err != nil { + return err + } + return os.Chmod(c.histPath, 0600) // Force 0600, even if it was different previously +} diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index bc8869b254..24fedd8d28 100644 --- a/internal/jsre/jsre.go +++ b/internal/jsre/jsre.go @@ -20,6 +20,7 @@ package jsre import ( crand "crypto/rand" "encoding/binary" + "errors" "fmt" "io" "io/ioutil" @@ -220,19 +221,33 @@ loop: } // Do executes the given function on the JS event loop. +// When the runtime is stopped, fn will not execute. func (re *JSRE) Do(fn func(*goja.Runtime)) { done := make(chan bool) req := &evalReq{fn, done} - re.evalQueue <- req - <-done + select { + case re.evalQueue <- req: + <-done + case <-re.closed: + } } -// stops the event loop before exit, optionally waits for all timers to expire +// Stop terminates the event loop, optionally waiting for all timers to expire. func (re *JSRE) Stop(waitForCallbacks bool) { - select { - case <-re.closed: - case re.stopEventLoop <- waitForCallbacks: - <-re.closed + timeout := time.NewTimer(10 * time.Millisecond) + defer timeout.Stop() + + for { + select { + case <-re.closed: + return + case re.stopEventLoop <- waitForCallbacks: + <-re.closed + return + case <-timeout.C: + // JS is blocked, interrupt and try again. + re.vm.Interrupt(errors.New("JS runtime stopped")) + } } } @@ -282,6 +297,19 @@ func (re *JSRE) Evaluate(code string, w io.Writer) { }) } +// Interrupt stops the current JS evaluation. +func (re *JSRE) Interrupt(v interface{}) { + done := make(chan bool) + noop := func(*goja.Runtime) {} + + select { + case re.evalQueue <- &evalReq{noop, done}: + // event loop is not blocked. + default: + re.vm.Interrupt(v) + } +} + // Compile compiles and then runs a piece of JS code. func (re *JSRE) Compile(filename string, src string) (err error) { re.Do(func(vm *goja.Runtime) { _, err = compileAndRun(vm, filename, src) }) From b3b8b268eb585dfd3c1c9e9bbebc55968f3bec4b Mon Sep 17 00:00:00 2001 From: jovijovi Date: Tue, 14 Dec 2021 17:17:25 +0800 Subject: [PATCH 07/12] consensus: define MaxGasLimit as a const in params (#24092) * consensus: use the maxGasLimit constant to check the header.GasLimit to avoid creating new variables repeatedly * consensus: check the header.GasLimit by the public constant MaxGasLimit * consensus: check the header.GasLimit by the constant MaxGasLimit --- consensus/beacon/consensus.go | 6 +++--- consensus/clique/clique.go | 5 ++--- consensus/ethash/consensus.go | 5 ++--- params/protocol_params.go | 7 ++++--- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index d904064385..9467fea67b 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" ) @@ -196,9 +197,8 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, beaconDifficulty) } // Verify that the gas limit is <= 2^63-1 - cap := uint64(0x7fffffffffffffff) - if header.GasLimit > cap { - return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) + if header.GasLimit > params.MaxGasLimit { + return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) } // Verify that the gasUsed is <= gasLimit if header.GasUsed > header.GasLimit { diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 38597e1526..685186817d 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -295,9 +295,8 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H } } // Verify that the gas limit is <= 2^63-1 - cap := uint64(0x7fffffffffffffff) - if header.GasLimit > cap { - return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) + if header.GasLimit > params.MaxGasLimit { + return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) } // If all checks passed, validate any special fields for hard forks if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 7fa427f68b..7dec436a26 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -281,9 +281,8 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected) } // Verify that the gas limit is <= 2^63-1 - cap := uint64(0x7fffffffffffffff) - if header.GasLimit > cap { - return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) + if header.GasLimit > params.MaxGasLimit { + return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) } // Verify that the gasUsed is <= gasLimit if header.GasUsed > header.GasLimit { diff --git a/params/protocol_params.go b/params/protocol_params.go index bc68d3580d..5f154597a7 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -19,9 +19,10 @@ package params import "math/big" const ( - GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations. - MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be. - GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block. + GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations. + MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be. + MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1). + GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block. MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction. From adec878c1d2d8b46f43d592856b2b5915f5a65fb Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 14 Dec 2021 18:11:05 +0800 Subject: [PATCH 08/12] core/rawdb: fix error message fields in ReadLogs (#24104) --- core/rawdb/accessors_chain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 7f46f9d72b..891349d5fa 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -714,7 +714,7 @@ func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.C if logs := readLegacyLogs(db, hash, number, config); logs != nil { return logs } - log.Error("Invalid receipt array RLP", "hash", "err", err) + log.Error("Invalid receipt array RLP", "hash", hash, "err", err) return nil } From 155795be99f232a583696b21ce294b77f0bdffc1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 14 Dec 2021 11:30:20 +0100 Subject: [PATCH 09/12] core/vm: avoid memory expansion check for trivial ops (#24048) --- core/vm/interpreter.go | 56 +++++++++++++++++++----------------------- core/vm/jump_table.go | 38 +++++++++++++++++++++------- 2 files changed, 54 insertions(+), 40 deletions(-) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 53f4acc849..1660e3ce0f 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -181,62 +181,56 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Capture pre-execution values for tracing. logged, pcCopy, gasCopy = false, pc, contract.Gas } - // Get the operation from the jump table and validate the stack to ensure there are // enough stack items available to perform the operation. op = contract.GetOp(pc) operation := in.cfg.JumpTable[op] + cost = operation.constantGas // For tracing // Validate stack if sLen := stack.len(); sLen < operation.minStack { return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack} } else if sLen > operation.maxStack { return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} } - // Static portion of gas - cost = operation.constantGas // For tracing - if !contract.UseGas(operation.constantGas) { + if !contract.UseGas(cost) { return nil, ErrOutOfGas } - - var memorySize uint64 - // calculate the new memory size and expand the memory to fit - // the operation - // Memory check needs to be done prior to evaluating the dynamic gas portion, - // to detect calculation overflows - if operation.memorySize != nil { - memSize, overflow := operation.memorySize(stack) - if overflow { - return nil, ErrGasUintOverflow - } - // memory is expanded in words of 32 bytes. Gas - // is also calculated in words. - if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { - return nil, ErrGasUintOverflow - } - } - // Dynamic portion of gas - // consume the gas and return an error if not enough gas is available. - // cost is explicitly set so that the capture state defer method can get the proper cost if operation.dynamicGas != nil { + // All ops with a dynamic memory usage also has a dynamic gas cost. + var memorySize uint64 + // calculate the new memory size and expand the memory to fit + // the operation + // Memory check needs to be done prior to evaluating the dynamic gas portion, + // to detect calculation overflows + if operation.memorySize != nil { + memSize, overflow := operation.memorySize(stack) + if overflow { + return nil, ErrGasUintOverflow + } + // memory is expanded in words of 32 bytes. Gas + // is also calculated in words. + if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { + return nil, ErrGasUintOverflow + } + } + // Consume the gas and return an error if not enough gas is available. + // cost is explicitly set so that the capture state defer method can get the proper cost var dynamicCost uint64 dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) - cost += dynamicCost // total cost, for debug tracing + cost += dynamicCost // for tracing if err != nil || !contract.UseGas(dynamicCost) { return nil, ErrOutOfGas } + if memorySize > 0 { + mem.Resize(memorySize) + } } - if memorySize > 0 { - mem.Resize(memorySize) - } - if in.cfg.Debug { in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) logged = true } - // execute the operation res, err = operation.execute(&pc, in, callContext) - if err != nil { break } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index bb559b5949..6dea5d81f3 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -17,6 +17,8 @@ package vm import ( + "fmt" + "github.com/ethereum/go-ethereum/params" ) @@ -57,13 +59,31 @@ var ( // JumpTable contains the EVM opcodes supported at a given fork. type JumpTable [256]*operation +func validate(jt JumpTable) JumpTable { + for i, op := range jt { + if op == nil { + panic(fmt.Sprintf("op 0x%x is not set", i)) + } + // The interpreter has an assumption that if the memorySize function is + // set, then the dynamicGas function is also set. This is a somewhat + // arbitrary assumption, and can be removed if we need to -- but it + // allows us to avoid a condition check. As long as we have that assumption + // in there, this little sanity check prevents us from merging in a + // change which violates it. + if op.memorySize != nil && op.dynamicGas == nil { + panic(fmt.Sprintf("op %v has dynamic memory but not dynamic gas", OpCode(i).String())) + } + } + return jt +} + // newLondonInstructionSet returns the frontier, homestead, byzantium, // contantinople, istanbul, petersburg, berlin and london instructions. func newLondonInstructionSet() JumpTable { instructionSet := newBerlinInstructionSet() enable3529(&instructionSet) // EIP-3529: Reduction in refunds https://eips.ethereum.org/EIPS/eip-3529 enable3198(&instructionSet) // Base fee opcode https://eips.ethereum.org/EIPS/eip-3198 - return instructionSet + return validate(instructionSet) } // newBerlinInstructionSet returns the frontier, homestead, byzantium, @@ -71,7 +91,7 @@ func newLondonInstructionSet() JumpTable { func newBerlinInstructionSet() JumpTable { instructionSet := newIstanbulInstructionSet() enable2929(&instructionSet) // Access lists for trie accesses https://eips.ethereum.org/EIPS/eip-2929 - return instructionSet + return validate(instructionSet) } // newIstanbulInstructionSet returns the frontier, homestead, byzantium, @@ -83,7 +103,7 @@ func newIstanbulInstructionSet() JumpTable { enable1884(&instructionSet) // Reprice reader opcodes - https://eips.ethereum.org/EIPS/eip-1884 enable2200(&instructionSet) // Net metered SSTORE - https://eips.ethereum.org/EIPS/eip-2200 - return instructionSet + return validate(instructionSet) } // newConstantinopleInstructionSet returns the frontier, homestead, @@ -122,7 +142,7 @@ func newConstantinopleInstructionSet() JumpTable { maxStack: maxStack(4, 1), memorySize: memoryCreate2, } - return instructionSet + return validate(instructionSet) } // newByzantiumInstructionSet returns the frontier, homestead and @@ -158,14 +178,14 @@ func newByzantiumInstructionSet() JumpTable { maxStack: maxStack(2, 0), memorySize: memoryRevert, } - return instructionSet + return validate(instructionSet) } // EIP 158 a.k.a Spurious Dragon func newSpuriousDragonInstructionSet() JumpTable { instructionSet := newTangerineWhistleInstructionSet() instructionSet[EXP].dynamicGas = gasExpEIP158 - return instructionSet + return validate(instructionSet) } @@ -179,7 +199,7 @@ func newTangerineWhistleInstructionSet() JumpTable { instructionSet[CALL].constantGas = params.CallGasEIP150 instructionSet[CALLCODE].constantGas = params.CallGasEIP150 instructionSet[DELEGATECALL].constantGas = params.CallGasEIP150 - return instructionSet + return validate(instructionSet) } // newHomesteadInstructionSet returns the frontier and homestead @@ -194,7 +214,7 @@ func newHomesteadInstructionSet() JumpTable { maxStack: maxStack(6, 1), memorySize: memoryDelegateCall, } - return instructionSet + return validate(instructionSet) } // newFrontierInstructionSet returns the frontier instructions @@ -1010,5 +1030,5 @@ func newFrontierInstructionSet() JumpTable { } } - return tbl + return validate(tbl) } From fc01a7ce8e4f865b0d282c21a42c21b0bd1d0b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Tue, 14 Dec 2021 11:34:50 +0100 Subject: [PATCH 10/12] les/vflux/client, p2p/nodestate: fix data races (#24058) Fixes #23848 --- les/vflux/client/serverpool_test.go | 39 +++++++++++++++++++++++++---- p2p/nodestate/nodestate.go | 9 ++++++- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/les/vflux/client/serverpool_test.go b/les/vflux/client/serverpool_test.go index 763f72f03a..c7d0245ef2 100644 --- a/les/vflux/client/serverpool_test.go +++ b/les/vflux/client/serverpool_test.go @@ -63,7 +63,11 @@ type ServerPoolTest struct { trusted []string waitCount, waitEnded int32 - lock sync.Mutex + // preNegLock protects the cycle counter, testNodes list and its connected field + // (accessed from both the main thread and the preNeg callback) + preNegLock sync.Mutex + queryWg *sync.WaitGroup // a new wait group is created each time the simulation is started + stopping bool // stopping avoid callind queryWg.Add after queryWg.Wait cycle, conn, servedConn int serviceCycles, dialCount int @@ -111,13 +115,21 @@ func (s *ServerPoolTest) addTrusted(i int) { func (s *ServerPoolTest) start() { var testQuery QueryFunc + s.queryWg = new(sync.WaitGroup) if s.preNeg { testQuery = func(node *enode.Node) int { + s.preNegLock.Lock() + if s.stopping { + s.preNegLock.Unlock() + return 0 + } + s.queryWg.Add(1) idx := testNodeIndex(node.ID()) n := &s.testNodes[idx] - s.lock.Lock() canConnect := !n.connected && n.connectCycles != 0 && s.cycle >= n.nextConnCycle - s.lock.Unlock() + s.preNegLock.Unlock() + defer s.queryWg.Done() + if s.preNegFail { // simulate a scenario where UDP queries never work s.beginWait() @@ -181,11 +193,20 @@ func (s *ServerPoolTest) start() { } func (s *ServerPoolTest) stop() { + // disable further queries and wait if one is currently running + s.preNegLock.Lock() + s.stopping = true + s.preNegLock.Unlock() + s.queryWg.Wait() + quit := make(chan struct{}) s.quit <- quit <-quit s.sp.Stop() s.spi.Close() + s.preNegLock.Lock() + s.stopping = false + s.preNegLock.Unlock() for i := range s.testNodes { n := &s.testNodes[i] if n.connected { @@ -205,7 +226,9 @@ func (s *ServerPoolTest) run() { n := &s.testNodes[idx] s.sp.UnregisterNode(n.node) n.totalConn += s.cycle + s.preNegLock.Lock() n.connected = false + s.preNegLock.Unlock() n.node = nil s.conn-- if n.service { @@ -230,7 +253,9 @@ func (s *ServerPoolTest) run() { s.servedConn++ } n.totalConn -= s.cycle + s.preNegLock.Lock() n.connected = true + s.preNegLock.Unlock() dc := s.cycle + n.connectCycles s.disconnect[dc] = append(s.disconnect[dc], idx) n.node = dial @@ -242,9 +267,9 @@ func (s *ServerPoolTest) run() { } s.serviceCycles += s.servedConn s.clock.Run(time.Second) - s.lock.Lock() + s.preNegLock.Lock() s.cycle++ - s.lock.Unlock() + s.preNegLock.Unlock() } } @@ -255,11 +280,13 @@ func (s *ServerPoolTest) setNodes(count, conn, wait int, service, trusted bool) idx = rand.Intn(spTestNodes) } res = append(res, idx) + s.preNegLock.Lock() s.testNodes[idx] = spTestNode{ connectCycles: conn, waitCycles: wait, service: service, } + s.preNegLock.Unlock() if trusted { s.addTrusted(idx) } @@ -273,7 +300,9 @@ func (s *ServerPoolTest) resetNodes() { n.totalConn += s.cycle s.sp.UnregisterNode(n.node) } + s.preNegLock.Lock() s.testNodes[i] = spTestNode{totalConn: n.totalConn} + s.preNegLock.Unlock() } s.conn, s.servedConn = 0, 0 s.disconnect = make(map[int][]int) diff --git a/p2p/nodestate/nodestate.go b/p2p/nodestate/nodestate.go index 9323d53cbd..2af0d0a6bd 100644 --- a/p2p/nodestate/nodestate.go +++ b/p2p/nodestate/nodestate.go @@ -808,7 +808,14 @@ func (ns *NodeStateMachine) addTimeout(n *enode.Node, mask bitMask, timeout time ns.removeTimeouts(node, mask) t := &nodeStateTimeout{mask: mask} t.timer = ns.clock.AfterFunc(timeout, func() { - ns.SetState(n, Flags{}, Flags{mask: t.mask, setup: ns.setup}, 0) + ns.lock.Lock() + defer ns.lock.Unlock() + + if !ns.opStart() { + return + } + ns.setState(n, Flags{}, Flags{mask: t.mask, setup: ns.setup}, 0) + ns.opFinish() }) node.timeouts = append(node.timeouts, t) if mask&ns.saveFlags != 0 { From 0ba0b81e54483978ab823665afb627ab4999db06 Mon Sep 17 00:00:00 2001 From: Roman Mazalov <83914728+gopherxyz@users.noreply.github.com> Date: Wed, 15 Dec 2021 14:30:54 +0000 Subject: [PATCH 11/12] rpc: fix time key collision for logger with json output (#24112) The "t" key overrides the log message time in JSON output. Co-authored-by: Felix Lange --- rpc/handler.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rpc/handler.go b/rpc/handler.go index 85f774a1b7..488a29300a 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -240,7 +240,7 @@ func (h *handler) handleImmediate(msg *jsonrpcMessage) bool { return false case msg.isResponse(): h.handleResponse(msg) - h.log.Trace("Handled RPC response", "reqid", idForLog{msg.ID}, "t", time.Since(start)) + h.log.Trace("Handled RPC response", "reqid", idForLog{msg.ID}, "duration", time.Since(start)) return true default: return false @@ -292,12 +292,12 @@ func (h *handler) handleCallMsg(ctx *callProc, msg *jsonrpcMessage) *jsonrpcMess switch { case msg.isNotification(): h.handleCall(ctx, msg) - h.log.Debug("Served "+msg.Method, "t", time.Since(start)) + h.log.Debug("Served "+msg.Method, "duration", time.Since(start)) return nil case msg.isCall(): resp := h.handleCall(ctx, msg) var ctx []interface{} - ctx = append(ctx, "reqid", idForLog{msg.ID}, "t", time.Since(start)) + ctx = append(ctx, "reqid", idForLog{msg.ID}, "duration", time.Since(start)) if resp.Error != nil { ctx = append(ctx, "err", resp.Error.Message) if resp.Error.Data != nil { From b8b3d2f69aaed2540551756e85ead6a5ea53c4a1 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 16 Dec 2021 10:40:24 +0100 Subject: [PATCH 12/12] README: remove mentions of snap sync --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b864671c8b..0e8bdca4db 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ on how you can run your own `geth` instance. By far the most common scenario is people wanting to simply interact with the Ethereum network: create accounts; transfer funds; deploy and interact with contracts. For this particular use-case the user doesn't care about years-old historical data, so we can -fast-sync quickly to the current state of the network. To do so: +sync quickly to the current state of the network. To do so: ```shell $ geth console @@ -159,7 +159,7 @@ docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \ ethereum/client-go ``` -This will start `geth` in fast-sync mode with a DB memory allowance of 1GB just as the +This will start `geth` in snap-sync mode with a DB memory allowance of 1GB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image.