Skip to content

Commit

Permalink
Merge tag 'v0.3.5' into merge/bor-v0.3.5
Browse files Browse the repository at this point in the history
Also updated some imports to conform with utils v0.0.24.
Added blockchain_hooks_test.go from main project.

Tests failing in cmd/geth/
  • Loading branch information
philip-morlier committed Mar 7, 2023
2 parents f82e69e + 7db8c14 commit 592c74f
Show file tree
Hide file tree
Showing 14 changed files with 206 additions and 37 deletions.
151 changes: 136 additions & 15 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,29 @@
package core

import (
"compress/gzip"
"context"
"errors"
"fmt"
"io"
"math/big"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"sync/atomic"
"time"

lru "github.com/hashicorp/golang-lru"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/common/prque"
"github.com/ethereum/go-ethereum/common/tracing"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
Expand Down Expand Up @@ -1353,43 +1361,89 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
}

// WriteBlockWithState writes the block and all associated state to the database.
func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
func (bc *BlockChain) WriteBlockAndSetHead(ctx context.Context, block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if !bc.chainmu.TryLock() {
return NonStatTy, errChainStopped
}
defer bc.chainmu.Unlock()

return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent)
return bc.writeBlockAndSetHead(ctx, block, receipts, logs, state, emitHeadEvent)
}

// writeBlockAndSetHead writes the block and all associated state to the database,
// and also it applies the given block as the new chain head. This function expects
// the chain mutex to be held.
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
func (bc *BlockChain) writeBlockAndSetHead(ctx context.Context, block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
writeBlockAndSetHeadCtx, span := tracing.StartSpan(ctx, "blockchain.writeBlockAndSetHead")
defer tracing.EndSpan(span)

var stateSyncLogs []*types.Log
if stateSyncLogs, err = bc.writeBlockWithState(block, receipts, logs, state); err != nil {

tracing.Exec(writeBlockAndSetHeadCtx, "blockchain.writeBlockWithState", func(_ context.Context, span trace.Span) {
stateSyncLogs, err = bc.writeBlockWithState(block, receipts, logs, state)
tracing.SetAttributes(
span,
attribute.Int("number", int(block.Number().Uint64())),
attribute.Bool("error", err != nil),
)
})

if err != nil {
return NonStatTy, err
}

currentBlock := bc.CurrentBlock()
reorg, err := bc.forker.ReorgNeeded(currentBlock.Header(), block.Header())

var reorg bool

tracing.Exec(writeBlockAndSetHeadCtx, "blockchain.ReorgNeeded", func(_ context.Context, span trace.Span) {
reorg, err = bc.forker.ReorgNeeded(currentBlock.Header(), block.Header())
tracing.SetAttributes(
span,
attribute.Int("number", int(block.Number().Uint64())),
attribute.Int("current block", int(currentBlock.Number().Uint64())),
attribute.Bool("reorg needed", reorg),
attribute.Bool("error", err != nil),
)
})
if err != nil {
return NonStatTy, err
}
if reorg {
// Reorganise the chain if the parent is not the head block
if block.ParentHash() != currentBlock.Hash() {
if err := bc.reorg(currentBlock, block); err != nil {
return NonStatTy, err

tracing.Exec(writeBlockAndSetHeadCtx, "blockchain.reorg", func(_ context.Context, span trace.Span) {
if reorg {
// Reorganise the chain if the parent is not the head block
if block.ParentHash() != currentBlock.Hash() {
if err = bc.reorg(currentBlock, block); err != nil {
status = NonStatTy
}
}
status = CanonStatTy
} else {
status = SideStatTy
}
status = CanonStatTy
} else {
status = SideStatTy

tracing.SetAttributes(
span,
attribute.Int("number", int(block.Number().Uint64())),
attribute.Int("current block", int(currentBlock.Number().Uint64())),
attribute.Bool("reorg needed", reorg),
attribute.Bool("error", err != nil),
attribute.String("status", string(status)),
)
})

if status == NonStatTy {
return
}

// Set new head.
if status == CanonStatTy {
bc.writeHeadBlock(block)
tracing.Exec(writeBlockAndSetHeadCtx, "blockchain.writeHeadBlock", func(_ context.Context, _ trace.Span) {
bc.writeHeadBlock(block)
})
}

bc.futureBlocks.Remove(block.Hash())

//begin PluGeth code injection
Expand Down Expand Up @@ -1798,7 +1852,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
// Don't set the head, only insert the block
_, err = bc.writeBlockWithState(block, receipts, logs, statedb)
} else {
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
status, err = bc.writeBlockAndSetHead(context.Background(), block, receipts, logs, statedb, false)
}
atomic.StoreUint32(&followupInterrupt, 1)
if err != nil {
Expand Down Expand Up @@ -2210,6 +2264,35 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
} else {
// len(newChain) == 0 && len(oldChain) > 0
// rewind the canonical chain to a lower point.

home, err := os.UserHomeDir()
if err != nil {
fmt.Println("Impossible reorg : Unable to get user home dir", "Error", err)
}
outPath := filepath.Join(home, "impossible-reorgs", fmt.Sprintf("%v-impossibleReorg", time.Now().Format(time.RFC3339)))

if _, err := os.Stat(outPath); errors.Is(err, os.ErrNotExist) {
err := os.MkdirAll(outPath, os.ModePerm)
if err != nil {
log.Error("Impossible reorg : Unable to create Dir", "Error", err)
}
} else {
err = ExportBlocks(oldChain, filepath.Join(outPath, "oldChain.gz"))
if err != nil {
log.Error("Impossible reorg : Unable to export oldChain", "Error", err)
}

err = ExportBlocks([]*types.Block{oldBlock}, filepath.Join(outPath, "oldBlock.gz"))
if err != nil {
log.Error("Impossible reorg : Unable to export oldBlock", "Error", err)
}

err = ExportBlocks([]*types.Block{newBlock}, filepath.Join(outPath, "newBlock.gz"))
if err != nil {
log.Error("Impossible reorg : Unable to export newBlock", "Error", err)
}
}

log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "oldblocks", len(oldChain), "newnum", newBlock.Number(), "newhash", newBlock.Hash(), "newblocks", len(newChain))
}
// Insert the new chain(except the head block(reverse order)),
Expand Down Expand Up @@ -2262,6 +2345,44 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
return nil
}

// ExportBlocks exports blocks into the specified file, truncating any data
// already present in the file.
func ExportBlocks(blocks []*types.Block, fn string) error {
log.Info("Exporting blockchain", "file", fn)

// Open the file handle and potentially wrap with a gzip stream
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil {
return err
}
defer fh.Close()

var writer io.Writer = fh
if strings.HasSuffix(fn, ".gz") {
writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close()
}
// Iterate over the blocks and export them
if err := ExportN(writer, blocks); err != nil {
return err
}

log.Info("Exported blocks", "file", fn)

return nil
}

// ExportBlock writes a block to the given writer.
func ExportN(w io.Writer, blocks []*types.Block) error {
for _, block := range blocks {
if err := block.EncodeRLP(w); err != nil {
return err
}
}

return nil
}

// InsertBlockWithoutSetHead executes the block, runs the necessary verification
// upon it and then persist the block and the associate state into the database.
// The key difference between the InsertChain is it won't do the canonical chain
Expand Down
29 changes: 29 additions & 0 deletions core/blockchain_hooks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package core

import (
"testing"
"math/big"
"github.com/ethereum/go-ethereum/plugins"
"github.com/openrelayxyz/plugeth-utils/core"
)

func TestReorgLongHeadersHook(t *testing.T) {
invoked := false
done := plugins.HookTester("NewHead", func(b []byte, h core.Hash, logs [][]byte, td *big.Int) {
invoked = true
if b == nil {
t.Errorf("Expected block to be non-nil")
}
if h == (core.Hash{}) {
t.Errorf("Expected hash to be non-empty")
}
if len(logs) > 0 {
t.Errorf("Expected some logs")
}
})
defer done()
testReorgLong(t, true)
if !invoked {
t.Errorf("Expected plugin invocation")
}
}
28 changes: 19 additions & 9 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/bn256"
"github.com/ethereum/go-ethereum/params"

//lint:ignore SA1019 Needed for precompile
big2 "github.com/holiman/big"
"golang.org/x/crypto/ripemd160"
)

Expand Down Expand Up @@ -266,9 +266,10 @@ var (
// modexpMultComplexity implements bigModexp multComplexity formula, as defined in EIP-198
//
// def mult_complexity(x):
// if x <= 64: return x ** 2
// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072
// else: return x ** 2 // 16 + 480 * x - 199680
//
// if x <= 64: return x ** 2
// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072
// else: return x ** 2 // 16 + 480 * x - 199680
//
// where is x is max(length_of_MODULUS, length_of_BASE)
func modexpMultComplexity(x *big.Int) *big.Int {
Expand Down Expand Up @@ -379,15 +380,24 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
}
// Retrieve the operands and execute the exponentiation
var (
base = new(big.Int).SetBytes(getData(input, 0, baseLen))
exp = new(big.Int).SetBytes(getData(input, baseLen, expLen))
mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen))
base = new(big2.Int).SetBytes(getData(input, 0, baseLen))
exp = new(big2.Int).SetBytes(getData(input, baseLen, expLen))
mod = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen))
v []byte
)
if mod.BitLen() == 0 {

switch {
case mod.BitLen() == 0:
// Modulo 0 is undefined, return zero
return common.LeftPadBytes([]byte{}, int(modLen)), nil
case base.BitLen() == 1: // a bit length of 1 means it's 1 (or -1).
//If base == 1, then we can just return base % mod (if mod >= 1, which it is)
v = base.Mod(base, mod).Bytes()
default:
v = base.Exp(base, exp, mod).Bytes()
}
return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil

return common.LeftPadBytes(v, int(modLen)), nil
}

// newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point,
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ require (
github.com/hashicorp/go-bexpr v0.1.10
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/hashicorp/hcl/v2 v2.10.1
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e
github.com/holiman/bloomfilter/v2 v2.0.3
github.com/holiman/uint256 v1.2.0
github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204
Expand All @@ -54,7 +55,7 @@ require (
github.com/mitchellh/cli v1.1.2
github.com/mitchellh/go-homedir v1.1.0
github.com/olekukonko/tablewriter v0.0.5
github.com/openrelayxyz/plugeth-utils v0.0.23
github.com/openrelayxyz/plugeth-utils v0.0.24
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
github.com/prometheus/tsdb v0.7.1
github.com/rjeczalik/notify v0.9.1
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuW
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl/v2 v2.10.1 h1:h4Xx4fsrRE26ohAk/1iGF/JBqRQbyUqu5Lvj60U54ys=
github.com/hashicorp/hcl/v2 v2.10.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw=
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
Expand Down Expand Up @@ -404,8 +406,8 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/openrelayxyz/plugeth-utils v0.0.23 h1:TKNGnRPWZ3mXNUHfjr1iRjsto2r6ngNZb95dJLj2j5w=
github.com/openrelayxyz/plugeth-utils v0.0.23/go.mod h1:zGm3/elx1rCcrYAFUQ5/He7AG/n039/3xYg0/Q8nqcQ=
github.com/openrelayxyz/plugeth-utils v0.0.24 h1:Q2BR3SlwHovNFLbEtGrFFqgOCnL+ONyrwTC9wKKAej4=
github.com/openrelayxyz/plugeth-utils v0.0.24/go.mod h1:W1Hwwhv04MCuNCcI6a62/kL6eWbH7OO+KvpBEyQTgIs=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
Expand Down
4 changes: 2 additions & 2 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,8 @@ func (w *worker) resultLoop() {
}

// Commit block and state to database.
tracing.ElapsedTime(ctx, span, "WriteBlockAndSetHead time taken", func(_ context.Context, _ trace.Span) {
_, err = w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true)
tracing.Exec(ctx, "resultLoop.WriteBlockAndSetHead", func(ctx context.Context, span trace.Span) {
_, err = w.chain.WriteBlockAndSetHead(ctx, block, receipts, logs, task.state, true)
})

tracing.SetAttributes(
Expand Down
8 changes: 7 additions & 1 deletion p2p/dnsdisc/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,19 @@ func TestClientSyncTree(t *testing.T) {

c := NewClient(Config{Resolver: r, Logger: testlog.Logger(t, log.LvlTrace)})
stree, err := c.SyncTree("enrtree://AKPYQIUQIL7PSIACI32J7FGZW56E5FKHEFCCOFHILBIMW3M6LWXS2@n")

if err != nil {
t.Fatal("sync error:", err)
}

if !reflect.DeepEqual(sortByID(stree.Nodes()), sortByID(wantNodes)) {
t.Errorf("wrong nodes in synced tree:\nhave %v\nwant %v", spew.Sdump(stree.Nodes()), spew.Sdump(wantNodes))
}

if !reflect.DeepEqual(stree.Links(), wantLinks) {
t.Errorf("wrong links in synced tree: %v", stree.Links())
}

if stree.Seq() != wantSeq {
t.Errorf("synced tree has wrong seq: %d", stree.Seq())
}
Expand Down Expand Up @@ -295,7 +299,7 @@ func TestIteratorEmptyTree(t *testing.T) {

// updateSomeNodes applies ENR updates to some of the given nodes.
func updateSomeNodes(keySeed int64, nodes []*enode.Node) {
keys := testKeys(nodesSeed1, len(nodes))
keys := testKeys(keySeed, len(nodes))
for i, n := range nodes[:len(nodes)/2] {
r := n.Record()
r.Set(enr.IP{127, 0, 0, 1})
Expand Down Expand Up @@ -384,10 +388,12 @@ func makeTestTree(domain string, nodes []*enode.Node, links []string) (*Tree, st
if err != nil {
panic(err)
}

url, err := tree.Sign(testKey(signingKeySeed), domain)
if err != nil {
panic(err)
}

return tree, url
}

Expand Down
Loading

0 comments on commit 592c74f

Please sign in to comment.