Compare commits

..

21 Commits

Author SHA1 Message Date
j75689
05c1f1438c chore: rialto network for testing 2024-03-15 09:56:52 +08:00
Roshan
4b5eebead1 fix review comments 2024-03-14 18:55:12 +08:00
Roshan
b5603d2e98 fix: add FeynmanFix upgrade for a testnet issue 2024-03-14 18:41:53 +08:00
Eric
c8cc91963f eth/gasprice: fix percentile validation in eth_feeHistory (#2242) 2024-03-04 10:53:21 +08:00
zzzckck
bd13416162 Merge pull request #2239 from bnb-chain/develop
draft release v1.3.10
2024-02-27 14:50:53 +08:00
zzzckck
b7b64da564 release: prepare for release v1.3.10 (#2238) 2024-02-27 14:19:32 +08:00
zjubfd
73f27a590f feat: add new fork block and precompile contract for BEP294 and BEP299 (#2047) 2024-02-26 16:17:03 +08:00
zzzckck
5e74ea650d Merge pull request #2218 from bnb-chain/develop
draft release v1.3.9
2024-02-20 17:52:32 +08:00
VM
5378df3702 cmd: optimize parse state scheme in cli and config (#2220) 2024-02-20 17:22:27 +08:00
Matus Kysel
40cae45436 Merge pull request #2213 from bnb-chain/freezer-fix
Freezer fix
2024-02-20 09:30:30 +01:00
zzzckck
361e8413e6 release: prepare for release v1.3.9 (#2217) 2024-02-19 14:43:15 +08:00
rjl493456442
36a283ef98 core/rawdb: fsync the index file after each freezer write (#28483)
* core/rawdb: fsync the index and data file after each freezer write

* core/rawdb: fsync the data file in freezer after write
2024-02-14 08:22:43 +01:00
Ng Wei Han
78d1cade19 eth/fetcher: downgrade state tx log (#2195) 2024-02-02 10:58:17 +08:00
Eric
82beb2c5f3 log: support maxBackups in config.toml (#2186) 2024-01-30 19:16:01 +08:00
Ng Wei Han
3761bf0426 fix(legacypool): deprecate already known error (#2190) 2024-01-29 19:13:15 +08:00
buddho
29427c51fd consensus/parlia: set nonce before evm run (#2185) 2024-01-29 14:44:58 +08:00
Matus Kysel
220be95117 Merge pull request #2183 from bnb-chain/fix-p2p-server-timeout
p2p: resolved deadlock on p2p server shutdown
2024-01-26 10:58:29 +01:00
Matus Kysel
f0d9f61bf6 p2p: return increased timeout 2024-01-26 09:29:43 +01:00
Matus Kysel
d49da4348c p2p: resolved deadlock on p2p server shutdown 2024-01-25 15:53:33 +01:00
VM
fecd2bfafe cmd: fix dump cli cannot work in path mode (#2160) 2024-01-25 22:07:44 +08:00
dependabot[bot]
ef13f3194d build(deps): bump github.com/quic-go/quic-go from 0.39.3 to 0.39.4 (#2177) 2024-01-23 17:41:20 +08:00
65 changed files with 6130 additions and 2167 deletions

View File

@@ -47,5 +47,3 @@ jobs:
run: |
go mod download
make geth

View File

@@ -44,7 +44,7 @@ jobs:
${{ runner.os }}-go-
- run: |
go mod download
go mod tidy
- name: golangci-lint
uses: golangci/golangci-lint-action@v3

37
.github/workflows/nancy.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Go Nancy
on:
# Scan changed files in PRs (diff-aware scanning):
pull_request: {}
# Scan on-demand through GitHub Actions interface:
workflow_dispatch: {}
# Scan mainline branches and report all findings:
push:
branches: ["master", "develop"]
jobs:
build:
strategy:
matrix:
go-version: [1.21.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Set up Go 1.x in order to write go.list file
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Go mod tidy
run: go mod tidy
- name: WriteGoList
run: go list -json -deps ./... > go.list
- name: Nancy
uses: sonatype-nexus-community/nancy-github-action@main
with:
nancyCommand: sleuth --loud

View File

@@ -51,4 +51,3 @@ jobs:
run: |
go mod download
make test

View File

@@ -1,4 +1,26 @@
# Changelog
## v1.3.11
BUGFIX
* [\#2288](https://github.com/bnb-chain/bsc/pull/2288) fix: add FeynmanFix upgrade for a testnet issue
## v1.3.10
FEATURE
* [\#2047](https://github.com/bnb-chain/bsc/pull/2047) feat: add new fork block and precompile contract for BEP294 and BEP299
## v1.3.9
FEATURE
* [\#2186](https://github.com/bnb-chain/bsc/pull/2186) log: support maxBackups in config.toml
BUGFIX
* [\#2160](https://github.com/bnb-chain/bsc/pull/2160) cmd: fix dump cli cannot work in path mode
* [\#2183](https://github.com/bnb-chain/bsc/pull/2183) p2p: resolved deadlock on p2p server shutdown
IMPROVEMENT
* [\#2177](https://github.com/bnb-chain/bsc/pull/0000) build(deps): bump github.com/quic-go/quic-go from 0.39.3 to 0.39.4
* [\#2185](https://github.com/bnb-chain/bsc/pull/2185) consensus/parlia: set nonce before evm run
* [\#2190](https://github.com/bnb-chain/bsc/pull/2190) fix(legacypool): deprecate already known error
* [\#2195](https://github.com/bnb-chain/bsc/pull/2195) eth/fetcher: downgrade state tx log
## v1.3.8
FEATURE
* [\#2074](https://github.com/bnb-chain/bsc/pull/2074) faucet: new faucet client

View File

@@ -2127,7 +2127,7 @@ func TestGolangBindings(t *testing.T) {
t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out)
}
replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/tendermint/tendermint@v0.0.0", "-replace", "github.com/tendermint/tendermint=github.com/bnb-chain/tendermint@v0.31.15") // Repo root
replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/tendermint/tendermint@v0.0.0", "-replace", "github.com/tendermint/tendermint=github.com/bnb-chain/tendermint@v0.31.16") // Repo root
replacer.Dir = pkg
if out, err := replacer.CombinedOutput(); err != nil {
t.Fatalf("failed to replace tendermint dependency to bnb-chain source: %v\n%s", err, out)

View File

@@ -360,7 +360,7 @@ func doLint(cmdline []string) {
// downloadLinter downloads and unpacks golangci-lint.
func downloadLinter(cachedir string) string {
const version = "1.52.2"
const version = "1.55.2"
csdb := build.MustLoadChecksums("build/checksums.txt")
arch := runtime.GOARCH

View File

@@ -5,6 +5,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"os"
"path/filepath"
"strings"
@@ -14,6 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/io/prompt"
validatorpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/validator-client"
"github.com/prysmaticlabs/prysm/v4/validator/accounts"
"github.com/prysmaticlabs/prysm/v4/validator/accounts/iface"
"github.com/prysmaticlabs/prysm/v4/validator/accounts/petnames"
@@ -25,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/signer/core"
)
@@ -46,6 +49,10 @@ var (
Usage: "Password file path for the imported BLS account , which contains the password to get the private key by decrypting the keystore file",
Category: flags.AccountCategory,
}
chainIdFlag = &cli.Int64Flag{
Name: "chain-id",
Usage: "The chain id of the network that the validator will be created at",
}
)
var (
@@ -188,6 +195,22 @@ Print summary of existing BLS accounts in the current BLS wallet.`,
Delete the selected BLS account from the BLS wallet.`,
},
{
Name: "generate-proof",
Usage: "Generate ownership proof for the selected BLS account from the BLS wallet",
Action: blsAccountGenerateProof,
ArgsUsage: "<BLS pubkey>",
Category: "BLS ACCOUNT COMMANDS",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.BLSPasswordFileFlag,
chainIdFlag,
},
Description: `
geth bls account generate-proof
Generate ownership proof for the selected BLS account from the BLS wallet. The proof is used to prove the ownership of the BLS account when creating validator on BSC after feynman upgrade.`,
},
},
},
},
@@ -607,3 +630,74 @@ func blsAccountDelete(ctx *cli.Context) error {
return nil
}
// blsAccountGenerateProof generate ownership proof for a selected BLS account.
func blsAccountGenerateProof(ctx *cli.Context) error {
addrString := ctx.Args().First()
if addrString == "" {
utils.Fatalf("Operator account must be given as argument.")
}
addr := common.HexToAddress(addrString)
blsPubkeyString := ctx.Args().Get(1)
if blsPubkeyString == "" {
utils.Fatalf("BLS pubkey must be given as argument.")
}
blsPubkeyBz, err := hex.DecodeString(strings.TrimPrefix(blsPubkeyString, "0x"))
if err != nil {
utils.Fatalf("Could not decode string %s as hex.", blsPubkeyString)
}
blsPublicKey, err := bls.PublicKeyFromBytes(blsPubkeyBz)
if err != nil {
utils.Fatalf("%#x is not a valid BLS public key.", blsPubkeyBz)
}
cfg := gethConfig{Node: defaultNodeConfig()}
// Load config file.
if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err)
}
}
utils.SetNodeConfig(ctx, &cfg.Node)
walletDir := filepath.Join(cfg.Node.DataDir, BLSWalletPath)
dirExists, err := wallet.Exists(walletDir)
if err != nil || !dirExists {
utils.Fatalf("BLS wallet not exists.")
}
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name)))
w, err := wallet.OpenWallet(context.Background(), &wallet.Config{
WalletDir: walletDir,
WalletPassword: walletPassword,
})
if err != nil {
utils.Fatalf("Open BLS wallet failed: %v.", err)
}
km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false})
if err != nil {
utils.Fatalf("Initialize key manager failed: %v.", err)
}
chainIdInt64 := ctx.Int64(chainIdFlag.Name)
if chainIdInt64 == 0 {
utils.Fatalf("Chain id is required.")
}
chainId := new(big.Int).SetInt64(chainIdInt64)
paddedChainIdBytes := make([]byte, 32)
copy(paddedChainIdBytes[32-len(chainId.Bytes()):], chainId.Bytes())
msgHash := crypto.Keccak256(append(addr.Bytes(), append(blsPublicKey.Marshal(), paddedChainIdBytes...)...))
req := &validatorpb.SignRequest{
PublicKey: blsPublicKey.Marshal(),
SigningRoot: msgHash,
}
sig, err := km.Sign(context.Background(), req)
if err != nil {
utils.Fatalf("Generate signature failed: %v.", err)
}
fmt.Printf("Proof: %#x\n", sig.Marshal())
return nil
}

View File

@@ -30,6 +30,9 @@ import (
"sync/atomic"
"time"
"github.com/olekukonko/tablewriter"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -44,7 +47,8 @@ import (
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
)
var (
@@ -191,6 +195,21 @@ It's deprecated, please use "geth db export" instead.
}, utils.DatabasePathFlags),
Description: `
This command dumps out the state for a given block (or latest, if none provided).
If you use "dump" command in path mode, please firstly use "dump-roothash" command to get all available state root hash.
`,
}
dumpRootHashCommand = &cli.Command{
Action: dumpAllRootHashInPath,
Name: "dump-roothash",
Usage: "Dump all available state root hash in path mode",
Flags: flags.Merge([]cli.Flag{
utils.StateSchemeFlag,
}, utils.DatabasePathFlags),
Description: `
The dump-roothash command dump all available state root hash in path mode.
If you use "dump" command in path mode, please note that it only keeps at most 129 blocks which belongs to diffLayer or diskLayer.
Therefore, you must specify the blockNumber or blockHash that locates in diffLayer or diskLayer.
"geth" will print all available blockNumber and related block state root hash, and you can query block hash by block number.
`,
}
)
@@ -590,11 +609,20 @@ func exportPreimages(ctx *cli.Context) error {
}
func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, ethdb.Database, common.Hash, error) {
db := utils.MakeChainDatabase(ctx, stack, true, false)
var header *types.Header
if ctx.NArg() > 1 {
return nil, nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg())
}
db := utils.MakeChainDatabase(ctx, stack, true, false)
scheme, err := rawdb.ParseStateScheme(ctx.String(utils.StateSchemeFlag.Name), db)
if err != nil {
return nil, nil, common.Hash{}, err
}
if scheme == rawdb.PathScheme {
fmt.Println("You are using geth dump in path mode, please use `geth dump-roothash` command to get all available blocks.")
}
header := &types.Header{}
if ctx.NArg() == 1 {
arg := ctx.Args().First()
if hashish(arg) {
@@ -617,11 +645,22 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
}
} else {
// Use latest
if scheme == rawdb.PathScheme {
triedb := trie.NewDatabase(db, &trie.Config{PathDB: pathdb.ReadOnly})
defer triedb.Close()
if stateRoot := triedb.Head(); stateRoot != (common.Hash{}) {
header.Root = stateRoot
} else {
return nil, nil, common.Hash{}, fmt.Errorf("no top state root hash in path db")
}
} else {
header = rawdb.ReadHeadHeader(db)
}
}
if header == nil {
return nil, nil, common.Hash{}, errors.New("no head block found")
}
startArg := common.FromHex(ctx.String(utils.StartKeyFlag.Name))
var start common.Hash
switch len(startArg) {
@@ -634,6 +673,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
default:
return nil, nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg)
}
var conf = &state.DumpConfig{
SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name),
SkipStorage: ctx.Bool(utils.ExcludeStorageFlag.Name),
@@ -641,9 +681,10 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
Start: start.Bytes(),
Max: ctx.Uint64(utils.DumpLimitFlag.Name),
}
conf.StateScheme = scheme
log.Info("State dump configured", "block", header.Number, "hash", header.Hash().Hex(),
"skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage,
"start", hexutil.Encode(conf.Start), "limit", conf.Max)
"skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage, "start", hexutil.Encode(conf.Start),
"limit", conf.Max, "state scheme", conf.StateScheme)
return conf, db, header.Root, nil
}
@@ -675,6 +716,29 @@ func dump(ctx *cli.Context) error {
return nil
}
func dumpAllRootHashInPath(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true, false)
defer db.Close()
triedb := trie.NewDatabase(db, &trie.Config{PathDB: pathdb.ReadOnly})
defer triedb.Close()
scheme, err := rawdb.ParseStateScheme(ctx.String(utils.StateSchemeFlag.Name), db)
if err != nil {
return err
}
if scheme == rawdb.HashScheme {
return errors.New("incorrect state scheme, you should use it in path mode")
}
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Block Number", "Block State Root Hash"})
table.AppendBulk(triedb.GetAllRooHash())
table.Render()
return nil
}
// hashish returns true for strings that look like hashes.
func hashish(x string) bool {
_, err := strconv.Atoi(x)

View File

@@ -198,6 +198,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
v := ctx.Uint64(utils.OverrideVerkle.Name)
cfg.Eth.OverrideVerkle = &v
}
if ctx.IsSet(utils.OverrideFeynman.Name) {
v := ctx.Uint64(utils.OverrideFeynman.Name)
cfg.Eth.OverrideFeynman = &v
}
backend, _ := utils.RegisterEthService(stack, &cfg.Eth)
// Configure log filter RPC API.

View File

@@ -74,6 +74,7 @@ var (
utils.OverrideKepler,
utils.OverrideCancun,
utils.OverrideVerkle,
utils.OverrideFeynman,
utils.EnablePersonal,
utils.TxPoolLocalsFlag,
utils.TxPoolNoLocalsFlag,
@@ -239,6 +240,7 @@ func init() {
removedbCommand,
dumpCommand,
dumpGenesisCommand,
dumpRootHashCommand,
// See accountcmd.go:
accountCommand,
walletCommand,

View File

@@ -18,7 +18,6 @@
package utils
import (
"bufio"
"context"
"crypto/ecdsa"
"encoding/hex"
@@ -315,6 +314,11 @@ var (
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideFeynman = &cli.Uint64Flag{
Name: "override.feynman",
Usage: "Manually specify the Feynman fork timestamp, overriding the bundled setting",
Category: flags.EthCategory,
}
SyncModeFlag = &flags.TextMarshalerFlag{
Name: "syncmode",
Usage: `Blockchain sync mode ("snap" or "full")`,
@@ -1884,7 +1888,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if ctx.IsSet(StateHistoryFlag.Name) {
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
}
scheme, err := compareCLIWithConfig(ctx)
scheme, err := ParseCLIAndConfigStateScheme(ctx.String(StateSchemeFlag.Name), cfg.StateScheme)
if err != nil {
Fatalf("%v", err)
}
@@ -2353,11 +2357,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
}
provided, err := compareCLIWithConfig(ctx)
if err != nil {
Fatalf("%v", err)
}
scheme, err := rawdb.ParseStateScheme(provided, chainDb)
scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), chainDb)
if err != nil {
Fatalf("%v", err)
}
@@ -2425,11 +2425,7 @@ func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, read
config := &trie.Config{
Preimages: preimage,
}
provided, err := compareCLIWithConfig(ctx)
if err != nil {
Fatalf("%v", err)
}
scheme, err := rawdb.ParseStateScheme(provided, disk)
scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), disk)
if err != nil {
Fatalf("%v", err)
}
@@ -2448,26 +2444,15 @@ func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, read
return trie.NewDatabase(disk, config)
}
func compareCLIWithConfig(ctx *cli.Context) (string, error) {
var (
cfgScheme string
err error
)
if file := ctx.String("config"); file != "" {
// we don't validate cfgScheme because it's already checked in cmd/geth/loadBaseConfig
if cfgScheme, err = scanConfigForStateScheme(file); err != nil {
log.Error("Failed to parse config file", "error", err)
return "", err
}
}
if !ctx.IsSet(StateSchemeFlag.Name) {
// ParseCLIAndConfigStateScheme parses state scheme in CLI and config.
func ParseCLIAndConfigStateScheme(cliScheme, cfgScheme string) (string, error) {
if cliScheme == "" {
if cfgScheme != "" {
log.Info("Use config state scheme", "config", cfgScheme)
}
return cfgScheme, nil
}
cliScheme := ctx.String(StateSchemeFlag.Name)
if !rawdb.ValidateStateScheme(cliScheme) {
return "", fmt.Errorf("invalid state scheme in CLI: %s", cliScheme)
}
@@ -2477,35 +2462,3 @@ func compareCLIWithConfig(ctx *cli.Context) (string, error) {
}
return "", fmt.Errorf("incompatible state scheme, CLI: %s, config: %s", cliScheme, cfgScheme)
}
func scanConfigForStateScheme(file string) (string, error) {
f, err := os.Open(file)
if err != nil {
return "", err
}
defer f.Close()
scanner := bufio.NewScanner(f)
targetStr := "StateScheme"
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, targetStr) {
return indexStateScheme(line), nil
}
}
if err = scanner.Err(); err != nil {
return "", err
}
return "", nil
}
func indexStateScheme(str string) string {
i1 := strings.Index(str, "\"")
i2 := strings.LastIndex(str, "\"")
if i1 != -1 && i2 != -1 && i1 < i2 {
return str[i1+1 : i2]
}
return ""
}

View File

@@ -18,13 +18,8 @@
package utils
import (
"os"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/ethereum/go-ethereum/core/rawdb"
)
func Test_SplitTagsFlag(t *testing.T) {
@@ -67,126 +62,3 @@ func Test_SplitTagsFlag(t *testing.T) {
})
}
}
func Test_parseConfig(t *testing.T) {
tests := []struct {
name string
fn func() string
wantedResult string
wantedIsErr bool
wantedErrStr string
}{
{
name: "path",
fn: func() string {
tomlString := `[Eth]NetworkId = 56StateScheme = "path"`
return createTempTomlFile(t, tomlString)
},
wantedResult: rawdb.PathScheme,
wantedIsErr: false,
wantedErrStr: "",
},
{
name: "hash",
fn: func() string {
tomlString := `[Eth]NetworkId = 56StateScheme = "hash"`
return createTempTomlFile(t, tomlString)
},
wantedResult: rawdb.HashScheme,
wantedIsErr: false,
wantedErrStr: "",
},
{
name: "empty state scheme",
fn: func() string {
tomlString := `[Eth]NetworkId = 56StateScheme = ""`
return createTempTomlFile(t, tomlString)
},
wantedResult: "",
wantedIsErr: false,
wantedErrStr: "",
},
{
name: "unset state scheme",
fn: func() string {
tomlString := `[Eth]NetworkId = 56`
return createTempTomlFile(t, tomlString)
},
wantedResult: "",
wantedIsErr: false,
wantedErrStr: "",
},
{
name: "failed to open file",
fn: func() string { return "" },
wantedResult: "",
wantedIsErr: true,
wantedErrStr: "open : no such file or directory",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := scanConfigForStateScheme(tt.fn())
if tt.wantedIsErr {
assert.Contains(t, err.Error(), tt.wantedErrStr)
} else {
assert.Nil(t, err)
}
assert.Equal(t, tt.wantedResult, result)
})
}
}
// createTempTomlFile is a helper function to create a temp file with the provided TOML content
func createTempTomlFile(t *testing.T, content string) string {
t.Helper()
dir := t.TempDir()
file, err := os.CreateTemp(dir, "config.toml")
if err != nil {
t.Fatalf("Unable to create temporary file: %v", err)
}
defer file.Close()
_, err = file.WriteString(content)
if err != nil {
t.Fatalf("Unable to write to temporary file: %v", err)
}
return file.Name()
}
func Test_parseString(t *testing.T) {
tests := []struct {
name string
arg string
wantResult string
}{
{
name: "hash string",
arg: "\"hash\"",
wantResult: rawdb.HashScheme,
},
{
name: "path string",
arg: "\"path\"",
wantResult: rawdb.PathScheme,
},
{
name: "empty string",
arg: "",
wantResult: "",
},
{
name: "empty string",
arg: "\"\"",
wantResult: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := indexStateScheme(tt.arg); got != tt.wantResult {
t.Errorf("parseString() = %v, want %v", got, tt.wantResult)
}
})
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
package parlia
import (
"container/heap"
"context"
"fmt"
"math"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/systemcontracts"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)
const SecondsPerDay uint64 = 86400
// the params should be two blocks' time(timestamp)
func sameDayInUTC(first, second uint64) bool {
return first/SecondsPerDay == second/SecondsPerDay
}
func isBreatheBlock(lastBlockTime, blockTime uint64) bool {
return lastBlockTime != 0 && !sameDayInUTC(lastBlockTime, blockTime)
}
// initializeFeynmanContract initialize new contracts of Feynman fork
func (p *Parlia) initializeFeynmanContract(state *state.StateDB, header *types.Header, chain core.ChainContext,
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool,
) error {
// method
method := "initialize"
// initialize contracts
contracts := []string{
systemcontracts.StakeHubContract,
systemcontracts.GovernorContract,
systemcontracts.GovTokenContract,
systemcontracts.TimelockContract,
systemcontracts.TokenRecoverPortalContract,
}
// get packed data
data, err := p.stakeHubABI.Pack(method)
if err != nil {
log.Error("Unable to pack tx for initialize feynman contracts", "error", err)
return err
}
for _, c := range contracts {
msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(c), data, common.Big0)
// apply message
log.Info("initialize feynman contract", "block number", header.Number.Uint64(), "contract", c)
err = p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
if err != nil {
return err
}
}
return nil
}
type ValidatorItem struct {
address common.Address
votingPower *big.Int
voteAddress []byte
}
// An ValidatorHeap is a max-heap of validator's votingPower.
type ValidatorHeap []ValidatorItem
func (h *ValidatorHeap) Len() int { return len(*h) }
func (h *ValidatorHeap) Less(i, j int) bool {
// We want topK validators with max voting power, so we need a max-heap
if (*h)[i].votingPower.Cmp((*h)[j].votingPower) == 0 {
return (*h)[i].address.Hex() < (*h)[j].address.Hex()
} else {
return (*h)[i].votingPower.Cmp((*h)[j].votingPower) == 1
}
}
func (h *ValidatorHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] }
func (h *ValidatorHeap) Push(x interface{}) {
*h = append(*h, x.(ValidatorItem))
}
func (h *ValidatorHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func (p *Parlia) updateValidatorSetV2(state *state.StateDB, header *types.Header, chain core.ChainContext,
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool,
) error {
// 1. get all validators and its voting power
blockNr := rpc.BlockNumberOrHashWithHash(header.ParentHash, false)
validatorItems, err := p.getValidatorElectionInfo(blockNr)
if err != nil {
return err
}
maxElectedValidators, err := p.getMaxElectedValidators(blockNr)
if err != nil {
return err
}
// 2. sort by voting power
eValidators, eVotingPowers, eVoteAddrs := getTopValidatorsByVotingPower(validatorItems, maxElectedValidators)
// 3. update validator set to system contract
method := "updateValidatorSetV2"
data, err := p.validatorSetABI.Pack(method, eValidators, eVotingPowers, eVoteAddrs)
if err != nil {
log.Error("Unable to pack tx for updateValidatorSetV2", "error", err)
return err
}
// get system message
msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(systemcontracts.ValidatorContract), data, common.Big0)
// apply message
return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
}
func (p *Parlia) getValidatorElectionInfo(blockNr rpc.BlockNumberOrHash) ([]ValidatorItem, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
method := "getValidatorElectionInfo"
toAddress := common.HexToAddress(systemcontracts.StakeHubContract)
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
data, err := p.stakeHubABI.Pack(method, big.NewInt(0), big.NewInt(0))
if err != nil {
log.Error("Unable to pack tx for getValidatorElectionInfo", "error", err)
return nil, err
}
msgData := (hexutil.Bytes)(data)
result, err := p.ethAPI.Call(ctx, ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &msgData,
}, blockNr, nil, nil)
if err != nil {
return nil, err
}
var validators []common.Address
var votingPowers []*big.Int
var voteAddrs [][]byte
var totalLength *big.Int
if err := p.stakeHubABI.UnpackIntoInterface(&[]interface{}{&validators, &votingPowers, &voteAddrs, &totalLength}, method, result); err != nil {
return nil, err
}
if totalLength.Int64() != int64(len(validators)) || totalLength.Int64() != int64(len(votingPowers)) || totalLength.Int64() != int64(len(voteAddrs)) {
return nil, fmt.Errorf("validator length not match")
}
validatorItems := make([]ValidatorItem, len(validators))
for i := 0; i < len(validators); i++ {
validatorItems[i] = ValidatorItem{
address: validators[i],
votingPower: votingPowers[i],
voteAddress: voteAddrs[i],
}
}
return validatorItems, nil
}
func (p *Parlia) getMaxElectedValidators(blockNr rpc.BlockNumberOrHash) (maxElectedValidators *big.Int, err error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
method := "maxElectedValidators"
toAddress := common.HexToAddress(systemcontracts.StakeHubContract)
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
data, err := p.stakeHubABI.Pack(method)
if err != nil {
log.Error("Unable to pack tx for maxElectedValidators", "error", err)
return nil, err
}
msgData := (hexutil.Bytes)(data)
result, err := p.ethAPI.Call(ctx, ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &msgData,
}, blockNr, nil, nil)
if err != nil {
return nil, err
}
if err := p.stakeHubABI.UnpackIntoInterface(&maxElectedValidators, method, result); err != nil {
return nil, err
}
return maxElectedValidators, nil
}
func getTopValidatorsByVotingPower(validatorItems []ValidatorItem, maxElectedValidators *big.Int) ([]common.Address, []uint64, [][]byte) {
var validatorHeap ValidatorHeap
for i := 0; i < len(validatorItems); i++ {
// only keep validators with voting power > 0
if validatorItems[i].votingPower.Cmp(big.NewInt(0)) == 1 {
validatorHeap = append(validatorHeap, validatorItems[i])
}
}
hp := &validatorHeap
heap.Init(hp)
topN := int(maxElectedValidators.Int64())
if topN > len(validatorHeap) {
topN = len(validatorHeap)
}
eValidators := make([]common.Address, topN)
eVotingPowers := make([]uint64, topN)
eVoteAddrs := make([][]byte, topN)
for i := 0; i < topN; i++ {
item := heap.Pop(hp).(ValidatorItem)
eValidators[i] = item.address
// as the decimal in BNB Beacon Chain is 1e8 and in BNB Smart Chain is 1e18, we need to divide it by 1e10
eVotingPowers[i] = new(big.Int).Div(item.votingPower, big.NewInt(1e10)).Uint64()
eVoteAddrs[i] = item.voteAddress
}
return eValidators, eVotingPowers, eVoteAddrs
}

View File

@@ -0,0 +1,166 @@
package parlia
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
)
func TestValidatorHeap(t *testing.T) {
testCases := []struct {
description string
k int64
validators []ValidatorItem
expected []common.Address
}{
{
description: "normal case",
k: 2,
validators: []ValidatorItem{
{
address: common.HexToAddress("0x1"),
votingPower: new(big.Int).Mul(big.NewInt(300), big.NewInt(1e10)),
voteAddress: []byte("0x1"),
},
{
address: common.HexToAddress("0x2"),
votingPower: new(big.Int).Mul(big.NewInt(200), big.NewInt(1e10)),
voteAddress: []byte("0x2"),
},
{
address: common.HexToAddress("0x3"),
votingPower: new(big.Int).Mul(big.NewInt(100), big.NewInt(1e10)),
voteAddress: []byte("0x3"),
},
},
expected: []common.Address{
common.HexToAddress("0x1"),
common.HexToAddress("0x2"),
},
},
{
description: "same voting power",
k: 2,
validators: []ValidatorItem{
{
address: common.HexToAddress("0x1"),
votingPower: new(big.Int).Mul(big.NewInt(300), big.NewInt(1e10)),
voteAddress: []byte("0x1"),
},
{
address: common.HexToAddress("0x2"),
votingPower: new(big.Int).Mul(big.NewInt(100), big.NewInt(1e10)),
voteAddress: []byte("0x2"),
},
{
address: common.HexToAddress("0x3"),
votingPower: new(big.Int).Mul(big.NewInt(100), big.NewInt(1e10)),
voteAddress: []byte("0x3"),
},
},
expected: []common.Address{
common.HexToAddress("0x1"),
common.HexToAddress("0x2"),
},
},
{
description: "zero voting power and k > len(validators)",
k: 5,
validators: []ValidatorItem{
{
address: common.HexToAddress("0x1"),
votingPower: new(big.Int).Mul(big.NewInt(300), big.NewInt(1e10)),
voteAddress: []byte("0x1"),
},
{
address: common.HexToAddress("0x2"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x2"),
},
{
address: common.HexToAddress("0x3"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x3"),
},
{
address: common.HexToAddress("0x4"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x4"),
},
},
expected: []common.Address{
common.HexToAddress("0x1"),
},
},
{
description: "zero voting power and k < len(validators)",
k: 2,
validators: []ValidatorItem{
{
address: common.HexToAddress("0x1"),
votingPower: new(big.Int).Mul(big.NewInt(300), big.NewInt(1e10)),
voteAddress: []byte("0x1"),
},
{
address: common.HexToAddress("0x2"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x2"),
},
{
address: common.HexToAddress("0x3"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x3"),
},
{
address: common.HexToAddress("0x4"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x4"),
},
},
expected: []common.Address{
common.HexToAddress("0x1"),
},
},
{
description: "all zero voting power",
k: 2,
validators: []ValidatorItem{
{
address: common.HexToAddress("0x1"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x1"),
},
{
address: common.HexToAddress("0x2"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x2"),
},
{
address: common.HexToAddress("0x3"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x3"),
},
{
address: common.HexToAddress("0x4"),
votingPower: big.NewInt(0),
voteAddress: []byte("0x4"),
},
},
expected: []common.Address{},
},
}
for _, tc := range testCases {
eligibleValidators, _, _ := getTopValidatorsByVotingPower(tc.validators, big.NewInt(tc.k))
// check
if len(eligibleValidators) != len(tc.expected) {
t.Errorf("expected %d, got %d", len(tc.expected), len(eligibleValidators))
}
for i := 0; i < len(tc.expected); i++ {
if eligibleValidators[i] != tc.expected[i] {
t.Errorf("expected %s, got %s", tc.expected[i].Hex(), eligibleValidators[i].Hex())
}
}
}
}

View File

@@ -6,7 +6,6 @@ import (
"encoding/hex"
"errors"
"fmt"
"io"
"math"
"math/big"
"math/rand"
@@ -91,6 +90,11 @@ var (
common.HexToAddress(systemcontracts.TokenHubContract): true,
common.HexToAddress(systemcontracts.RelayerIncentivizeContract): true,
common.HexToAddress(systemcontracts.CrossChainContract): true,
common.HexToAddress(systemcontracts.StakeHubContract): true,
common.HexToAddress(systemcontracts.GovernorContract): true,
common.HexToAddress(systemcontracts.GovTokenContract): true,
common.HexToAddress(systemcontracts.TimelockContract): true,
common.HexToAddress(systemcontracts.TokenRecoverPortalContract): true,
}
)
@@ -180,7 +184,7 @@ func ecrecover(header *types.Header, sigCache *lru.ARCCache, chainId *big.Int) (
signature := header.Extra[len(header.Extra)-extraSeal:]
// Recover the public key and the Ethereum address
pubkey, err := crypto.Ecrecover(SealHash(header, chainId).Bytes(), signature)
pubkey, err := crypto.Ecrecover(types.SealHash(header, chainId).Bytes(), signature)
if err != nil {
return common.Address{}, err
}
@@ -200,7 +204,7 @@ func ecrecover(header *types.Header, sigCache *lru.ARCCache, chainId *big.Int) (
// or not), which could be abused to produce different hashes for the same header.
func ParliaRLP(header *types.Header, chainId *big.Int) []byte {
b := new(bytes.Buffer)
encodeSigHeader(b, header, chainId)
types.EncodeSigHeader(b, header, chainId)
return b.Bytes()
}
@@ -227,6 +231,7 @@ type Parlia struct {
validatorSetABIBeforeLuban abi.ABI
validatorSetABI abi.ABI
slashABI abi.ABI
stakeHubABI abi.ABI
// The fields below are for testing only
fakeDiff bool // Skip difficulty verifications
@@ -269,6 +274,10 @@ func New(
if err != nil {
panic(err)
}
stABI, err := abi.JSON(strings.NewReader(stakeABI))
if err != nil {
panic(err)
}
c := &Parlia{
chainConfig: chainConfig,
config: parliaConfig,
@@ -280,6 +289,7 @@ func New(
validatorSetABIBeforeLuban: vABIBeforeLuban,
validatorSetABI: vABI,
slashABI: sABI,
stakeHubABI: stABI,
signer: types.LatestSigner(chainConfig),
}
@@ -1117,6 +1127,22 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
cx := chainContext{Chain: chain, parlia: p}
parent := chain.GetHeaderByHash(header.ParentHash)
if parent == nil {
return errors.New("parent not found")
}
if p.chainConfig.IsFeynman(header.Number, header.Time) {
systemcontracts.UpgradeBuildInSystemContract(p.chainConfig, header.Number, parent.Time, header.Time, state)
}
if p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) {
err := p.initializeFeynmanContract(state, header, cx, txs, receipts, systemTxs, usedGas, false)
if err != nil {
log.Error("init feynman contract failed", "error", err)
}
}
// No block rewards in PoA, so the state remains as is and uncles are dropped
if header.Number.Cmp(common.Big1) == 0 {
err := p.initContract(state, header, cx, txs, receipts, systemTxs, usedGas, false)
@@ -1158,6 +1184,17 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
return err
}
}
// update validators every day
if p.chainConfig.IsFeynman(header.Number, header.Time) && isBreatheBlock(parent.Time, header.Time) {
// we should avoid update validators in the Feynman upgrade block
if !p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) {
if err := p.updateValidatorSetV2(state, header, cx, txs, receipts, systemTxs, usedGas, false); err != nil {
return err
}
}
}
if len(*systemTxs) > 0 {
return errors.New("the length of systemTxs do not match")
}
@@ -1176,6 +1213,23 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
if receipts == nil {
receipts = make([]*types.Receipt, 0)
}
parent := chain.GetHeaderByHash(header.ParentHash)
if parent == nil {
return nil, nil, errors.New("parent not found")
}
if p.chainConfig.IsFeynman(header.Number, header.Time) {
systemcontracts.UpgradeBuildInSystemContract(p.chainConfig, header.Number, parent.Time, header.Time, state)
}
if p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) {
err := p.initializeFeynmanContract(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true)
if err != nil {
log.Error("init feynman contract failed", "error", err)
}
}
if header.Number.Cmp(common.Big1) == 0 {
err := p.initContract(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true)
if err != nil {
@@ -1220,6 +1274,16 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
}
}
// update validators every day
if p.chainConfig.IsFeynman(header.Number, header.Time) && isBreatheBlock(parent.Time, header.Time) {
// we should avoid update validators in the Feynman upgrade block
if !p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) {
if err := p.updateValidatorSetV2(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true); err != nil {
return nil, nil, err
}
}
}
// should not happen. Once happen, stop the node is better than broadcast the block
if header.GasLimit < header.GasUsed {
return nil, nil, errors.New("gas consumption of system txs exceed the gas limit")
@@ -1422,7 +1486,7 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res
select {
case results <- block.WithSeal(header):
default:
log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header, p.chainConfig.ChainID))
log.Warn("Sealing result is not read by miner", "sealhash", types.SealHash(header, p.chainConfig.ChainID))
}
}()
@@ -1496,7 +1560,7 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int {
// So it's not the real hash of a block, just used as unique id to distinguish task
func (p *Parlia) SealHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewLegacyKeccak256()
encodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
types.EncodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
hasher.Sum(hash[:0])
return hash
}
@@ -1554,19 +1618,18 @@ func (p *Parlia) getCurrentValidators(blockHash common.Hash, blockNum *big.Int)
var valSet []common.Address
var voteAddrSet []types.BLSPublicKey
if err := p.validatorSetABI.UnpackIntoInterface(&[]interface{}{&valSet, &voteAddrSet}, method, result); err != nil {
return nil, nil, err
}
voteAddrmap := make(map[common.Address]*types.BLSPublicKey, len(valSet))
voteAddrMap := make(map[common.Address]*types.BLSPublicKey, len(valSet))
for i := 0; i < len(valSet); i++ {
voteAddrmap[valSet[i]] = &(voteAddrSet)[i]
voteAddrMap[valSet[i]] = &(voteAddrSet)[i]
}
return valSet, voteAddrmap, nil
return valSet, voteAddrMap, nil
}
// slash spoiled validators
// distributeIncoming distributes system incoming of the block
func (p *Parlia) distributeIncoming(val common.Address, state *state.StateDB, header *types.Header, chain core.ChainContext,
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool) error {
coinbase := header.Coinbase
@@ -1580,7 +1643,7 @@ func (p *Parlia) distributeIncoming(val common.Address, state *state.StateDB, he
doDistributeSysReward := !p.chainConfig.IsKepler(header.Number, header.Time) &&
state.GetBalance(common.HexToAddress(systemcontracts.SystemRewardContract)).Cmp(maxSystemBalance) < 0
if doDistributeSysReward {
var rewards = new(big.Int)
rewards := new(big.Int)
rewards = rewards.Rsh(balance, systemRewardPercent)
if rewards.Cmp(common.Big0) > 0 {
err := p.distributeToSystem(rewards, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
@@ -1656,7 +1719,7 @@ func (p *Parlia) distributeToSystem(amount *big.Int, state *state.StateDB, heade
return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
}
// slash spoiled validators
// distributeToValidator deposits validator reward to validator contract
func (p *Parlia) distributeToValidator(amount *big.Int, validator common.Address,
state *state.StateDB, header *types.Header, chain core.ChainContext,
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool) error {
@@ -1751,7 +1814,6 @@ func (p *Parlia) applyTransaction(
receipt.BlockNumber = header.Number
receipt.TransactionIndex = uint(state.TxIndex())
*receipts = append(*receipts, receipt)
state.SetNonce(msg.From(), nonce+1)
return nil
}
@@ -1802,62 +1864,6 @@ func (p *Parlia) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *t
}
// =========================== utility function ==========================
// SealHash returns the hash of a block prior to it being sealed.
func SealHash(header *types.Header, chainId *big.Int) (hash common.Hash) {
hasher := sha3.NewLegacyKeccak256()
encodeSigHeader(hasher, header, chainId)
hasher.Sum(hash[:0])
return hash
}
func encodeSigHeader(w io.Writer, header *types.Header, chainId *big.Int) {
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader
header.MixDigest,
header.Nonce,
})
if err != nil {
panic("can't encode: " + err.Error())
}
}
func encodeSigHeaderWithoutVoteAttestation(w io.Writer, header *types.Header, chainId *big.Int) {
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
header.MixDigest,
header.Nonce,
})
if err != nil {
panic("can't encode: " + err.Error())
}
}
func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Address) uint64 {
if snap.inturn(val) {
return 0
@@ -1975,6 +1981,8 @@ func applyMessage(
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, vm.TxContext{Origin: msg.From(), GasPrice: big.NewInt(0)}, state, chainConfig, vm.Config{})
// Apply the transaction to the current state (included in the env)
// Increment the nonce for the next transaction
state.SetNonce(msg.From(), state.GetNonce(msg.From())+1)
ret, returnGas, err := vmenv.Call(
vm.AccountRef(msg.From()),
*msg.To(),

View File

@@ -312,7 +312,11 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
misc.ApplyDAOHardFork(statedb)
}
if !config.IsFeynman(b.header.Number, b.header.Time) {
systemcontracts.UpgradeBuildInSystemContract(config, b.header.Number, parent.Time(), b.header.Time, statedb)
}
// Execute any user modifications to the block
if gen != nil {
gen(i, b)

View File

@@ -280,6 +280,8 @@ type ChainOverrides struct {
OverrideKepler *uint64
OverrideCancun *uint64
OverrideVerkle *uint64
OverrideFeynman *uint64
OverrideFeynmanFix *uint64
}
// SetupGenesisBlock writes or updates the genesis block in db.
@@ -317,6 +319,12 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
if overrides != nil && overrides.OverrideVerkle != nil {
config.VerkleTime = overrides.OverrideVerkle
}
if overrides != nil && overrides.OverrideFeynman != nil {
config.FeynmanTime = overrides.OverrideFeynman
}
if overrides != nil && overrides.OverrideFeynmanFix != nil {
config.FeynmanFixTime = overrides.OverrideFeynmanFix
}
}
}
// Just commit the new block if there is no stored genesis block.

View File

@@ -335,7 +335,7 @@ func ParseStateScheme(provided string, disk ethdb.Database) (string, error) {
if stored == "" {
// use default scheme for empty database, flip it when
// path mode is chosen as default
log.Info("State schema set to default", "scheme", "hash")
log.Info("State scheme set to default", "scheme", "hash")
return HashScheme, nil
}
log.Info("State scheme set to already existing disk db", "scheme", stored)

View File

@@ -129,6 +129,8 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
switch freezerName {
case chainFreezerName:
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
case stateFreezerName:
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
default:
return fmt.Errorf("unknown freezer, supported ones: %v", freezers)
}

View File

@@ -188,19 +188,27 @@ func (batch *freezerTableBatch) maybeCommit() error {
// commit writes the batched items to the backing freezerTable.
func (batch *freezerTableBatch) commit() error {
// Write data.
// Write data. The head file is fsync'd after write to ensure the
// data is truly transferred to disk.
_, err := batch.t.head.Write(batch.dataBuffer)
if err != nil {
return err
}
if err := batch.t.head.Sync(); err != nil {
return err
}
dataSize := int64(len(batch.dataBuffer))
batch.dataBuffer = batch.dataBuffer[:0]
// Write indices.
// Write indices. The index file is fsync'd after write to ensure the
// data indexes are truly transferred to disk.
_, err = batch.t.index.Write(batch.indexBuffer)
if err != nil {
return err
}
if err := batch.t.index.Sync(); err != nil {
return err
}
indexSize := int64(len(batch.indexBuffer))
batch.indexBuffer = batch.indexBuffer[:0]

View File

@@ -223,7 +223,9 @@ func (t *freezerTable) repair() error {
if t.readonly {
return fmt.Errorf("index file(path: %s, name: %s) size is not a multiple of %d", t.path, t.name, indexEntrySize)
}
truncateFreezerFile(t.index, stat.Size()-overflow) // New file can't trigger this path
if err := truncateFreezerFile(t.index, stat.Size()-overflow); err != nil {
return err
} // New file can't trigger this path
}
// Retrieve the file sizes and prepare for truncation
if stat, err = t.index.Stat(); err != nil {
@@ -268,8 +270,8 @@ func (t *freezerTable) repair() error {
// Print an error log if the index is corrupted due to an incorrect
// last index item. While it is theoretically possible to have a zero offset
// by storing all zero-size items, it is highly unlikely to occur in practice.
if lastIndex.offset == 0 && offsetsSize%indexEntrySize > 1 {
log.Error("Corrupted index file detected", "lastOffset", lastIndex.offset, "items", offsetsSize%indexEntrySize-1)
if lastIndex.offset == 0 && offsetsSize/indexEntrySize > 1 {
log.Error("Corrupted index file detected", "lastOffset", lastIndex.offset, "indexes", offsetsSize/indexEntrySize)
}
if t.readonly {
t.head, err = t.openFile(lastIndex.filenum, openFreezerFileForReadOnly)
@@ -424,6 +426,9 @@ func (t *freezerTable) truncateHead(items uint64) error {
if err := truncateFreezerFile(t.index, int64(length+1)*indexEntrySize); err != nil {
return err
}
if err := t.index.Sync(); err != nil {
return err
}
// Calculate the new expected size of the data file and truncate it
var expected indexEntry
if length == 0 {
@@ -446,6 +451,7 @@ func (t *freezerTable) truncateHead(items uint64) error {
// Release any files _after the current head -- both the previous head
// and any files which may have been opened for reading
t.releaseFilesAfter(expected.filenum, true)
// Set back the historic head
t.head = newHead
t.headId = expected.filenum
@@ -453,6 +459,9 @@ func (t *freezerTable) truncateHead(items uint64) error {
if err := truncateFreezerFile(t.head, int64(expected.offset)); err != nil {
return err
}
if err := t.head.Sync(); err != nil {
return err
}
// All data files truncated, set internal counters and return
t.headBytes = int64(expected.offset)
t.items.Store(items)
@@ -597,10 +606,12 @@ func (t *freezerTable) Close() error {
// error on Windows.
doClose(t.index, true, true)
doClose(t.meta, true, true)
// The preopened non-head data-files are all opened in readonly.
// The head is opened in rw-mode, so we sync it here - but since it's also
// part of t.files, it will be closed in the loop below.
doClose(t.head, true, false) // sync but do not close
for _, f := range t.files {
doClose(f, false, true) // close but do not sync
}

View File

@@ -73,11 +73,7 @@ func copyFrom(srcPath, destPath string, offset uint64, before func(f *os.File) e
return err
}
f = nil
if err := os.Rename(fname, destPath); err != nil {
return err
}
return nil
return os.Rename(fname, destPath)
}
// openFreezerFileForAppend opens a freezer table file and seeks to the end

View File

@@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
@@ -37,6 +38,7 @@ type DumpConfig struct {
OnlyWithAddresses bool
Start []byte
Max uint64
StateScheme string
}
// DumpCollector interface which the state trie calls during iteration
@@ -57,7 +59,6 @@ type DumpAccount struct {
Storage map[common.Hash]string `json:"storage,omitempty"`
Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode
SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key
}
// Dump represents the full dump in a collected format, as one large map.
@@ -177,7 +178,13 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
}
if !conf.SkipStorage {
account.Storage = make(map[common.Hash]string)
tr, err := obj.getTrie()
var tr Trie
if conf.StateScheme == rawdb.PathScheme {
tr, err = trie.NewStateTrie(trie.StorageTrieID(obj.db.originalRoot, common.BytesToHash(it.Key),
obj.data.Root), obj.db.db.TrieDB())
} else {
tr, err = obj.getTrie()
}
if err != nil {
log.Error("Failed to load storage trie", "err", err)
continue

View File

@@ -73,12 +73,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb)
}
// Handle upgrade build-in system contract code
lastBlock := p.bc.GetBlockByHash(block.ParentHash())
if lastBlock == nil {
return statedb, nil, nil, 0, fmt.Errorf("could not get parent block")
}
if !p.config.IsFeynman(block.Number(), block.Time()) {
// Handle upgrade build-in system contract code
systemcontracts.UpgradeBuildInSystemContract(p.config, blockNumber, lastBlock.Time(), block.Time(), statedb)
}
var (
context = NewEVMBlockContext(header, p.bc, nil)

View File

@@ -13,4 +13,10 @@ const (
TokenManagerContract = "0x0000000000000000000000000000000000001008"
CrossChainContract = "0x0000000000000000000000000000000000002000"
StakingContract = "0x0000000000000000000000000000000000002001"
StakeHubContract = "0x0000000000000000000000000000000000002002"
StakeCreditContract = "0x0000000000000000000000000000000000002003"
GovernorContract = "0x0000000000000000000000000000000000002004"
GovTokenContract = "0x0000000000000000000000000000000000002005"
TimelockContract = "0x0000000000000000000000000000000000002006"
TokenRecoverPortalContract = "0x0000000000000000000000000000000000003000"
)

File diff suppressed because one or more lines are too long

View File

@@ -57,10 +57,6 @@ const (
)
var (
// ErrAlreadyKnown is returned if the transactions is already contained
// within the pool.
ErrAlreadyKnown = errors.New("already known")
// ErrTxPoolOverflow is returned if the transaction pool is full and can't accept
// another remote transaction.
ErrTxPoolOverflow = errors.New("txpool is full")
@@ -715,7 +711,7 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
if pool.all.Get(hash) != nil {
log.Trace("Discarding already known transaction", "hash", hash)
knownTxMeter.Mark(1)
return false, ErrAlreadyKnown
return false, txpool.ErrAlreadyKnown
}
// Make the local flag. If it's from local source or it's from the network but
// the sender is marked as local previously, treat it as the local transaction.
@@ -1038,7 +1034,7 @@ func (pool *LegacyPool) addTxs(txs []*types.Transaction, local, sync bool) []err
for i, tx := range txs {
// If the transaction is known, pre-set the error slot
if pool.all.Get(tx.Hash()) != nil {
errs[i] = ErrAlreadyKnown
errs[i] = txpool.ErrAlreadyKnown
knownTxMeter.Mark(1)
continue
}

View File

@@ -26,6 +26,8 @@ import (
"sync/atomic"
"time"
"golang.org/x/crypto/sha3"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
@@ -560,8 +562,7 @@ func (d *DiffLayer) DecodeRLP(s *rlp.Stream) error {
if err := s.Decode(&ed); err != nil {
return err
}
d.BlockHash, d.Number, d.Codes, d.Destructs, d.Accounts, d.Storages =
ed.BlockHash, ed.Number, ed.Codes, ed.Destructs, ed.Accounts, ed.Storages
d.BlockHash, d.Number, d.Codes, d.Destructs, d.Accounts, d.Storages = ed.BlockHash, ed.Number, ed.Codes, ed.Destructs, ed.Accounts, ed.Storages
d.Receipts = make([]*Receipt, len(ed.Receipts))
for i, storageReceipt := range ed.Receipts {
@@ -608,6 +609,7 @@ func (storage *DiffStorage) Swap(i, j int) {
storage.Keys[i], storage.Keys[j] = storage.Keys[j], storage.Keys[i]
storage.Vals[i], storage.Vals[j] = storage.Vals[j], storage.Vals[i]
}
func (storage *DiffStorage) Less(i, j int) bool {
return string(storage.Keys[i][:]) < string(storage.Keys[j][:])
}
@@ -622,3 +624,64 @@ type DiffAccountsInBlock struct {
BlockHash common.Hash
Transactions []DiffAccountsInTx
}
var (
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
)
// SealHash returns the hash of a block prior to it being sealed.
func SealHash(header *Header, chainId *big.Int) (hash common.Hash) {
hasher := sha3.NewLegacyKeccak256()
EncodeSigHeader(hasher, header, chainId)
hasher.Sum(hash[:0])
return hash
}
func EncodeSigHeader(w io.Writer, header *Header, chainId *big.Int) {
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader
header.MixDigest,
header.Nonce,
})
if err != nil {
panic("can't encode: " + err.Error())
}
}
func EncodeSigHeaderWithoutVoteAttestation(w io.Writer, header *Header, chainId *big.Int) {
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
header.MixDigest,
header.Nonce,
})
if err != nil {
panic("can't encode: " + err.Error())
}
}

View File

@@ -17,23 +17,28 @@
package vm
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"math/big"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"golang.org/x/crypto/ripemd160"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/blake2b"
"github.com/ethereum/go-ethereum/crypto/bls12381"
"github.com/ethereum/go-ethereum/crypto/bn256"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"golang.org/x/crypto/ripemd160"
"github.com/ethereum/go-ethereum/rlp"
)
// PrecompiledContract is the basic interface for native Go contracts. The implementation
@@ -217,6 +222,29 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{101}): &iavlMerkleProofValidatePlato{},
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
common.BytesToAddress([]byte{103}): &cometBFTLightBlockValidate{},
common.BytesToAddress([]byte{104}): &verifyDoubleSignEvidence{},
common.BytesToAddress([]byte{105}): &secp256k1SignatureRecover{},
}
// PrecompiledContractsFeynman contains the default set of pre-compiled Ethereum
// contracts used in the Feynman release.
var PrecompiledContractsFeynman = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{100}): &tmHeaderValidate{},
common.BytesToAddress([]byte{101}): &iavlMerkleProofValidatePlato{},
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
common.BytesToAddress([]byte{103}): &cometBFTLightBlockValidateHertz{},
common.BytesToAddress([]byte{104}): &verifyDoubleSignEvidence{},
common.BytesToAddress([]byte{105}): &secp256k1SignatureRecover{},
}
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
@@ -245,6 +273,7 @@ var (
PrecompiledAddressesIstanbul []common.Address
PrecompiledAddressesByzantium []common.Address
PrecompiledAddressesHomestead []common.Address
PrecompiledAddressesFeynman []common.Address
)
func init() {
@@ -281,6 +310,9 @@ func init() {
for k := range PrecompiledContractsCancun {
PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k)
}
for k := range PrecompiledContractsFeynman {
PrecompiledAddressesFeynman = append(PrecompiledAddressesFeynman, k)
}
}
// ActivePrecompiles returns the precompiles enabled with the current configuration.
@@ -288,6 +320,8 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
switch {
case rules.IsCancun:
return PrecompiledAddressesCancun
case rules.IsFeynman:
return PrecompiledAddressesFeynman
case rules.IsHertz:
return PrecompiledAddressesHertz
case rules.IsPlato:
@@ -1355,3 +1389,95 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
return h
}
// verifyDoubleSignEvidence implements bsc header verification precompile.
type verifyDoubleSignEvidence struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *verifyDoubleSignEvidence) RequiredGas(input []byte) uint64 {
return params.DoubleSignEvidenceVerifyGas
}
type DoubleSignEvidence struct {
ChainId *big.Int
HeaderBytes1 []byte
HeaderBytes2 []byte
}
const (
extraSeal = 65
)
var (
errInvalidEvidence = errors.New("invalid double sign evidence")
)
// Run input: rlp encoded DoubleSignEvidence
// return:
// signer address| evidence height|
// 20 bytes | 32 bytes |
func (c *verifyDoubleSignEvidence) Run(input []byte) ([]byte, error) {
evidence := &DoubleSignEvidence{}
err := rlp.DecodeBytes(input, evidence)
if err != nil {
return nil, ErrExecutionReverted
}
header1 := &types.Header{}
err = rlp.DecodeBytes(evidence.HeaderBytes1, header1)
if err != nil {
return nil, ErrExecutionReverted
}
header2 := &types.Header{}
err = rlp.DecodeBytes(evidence.HeaderBytes2, header2)
if err != nil {
return nil, ErrExecutionReverted
}
// basic check
if len(header1.Number.Bytes()) > 32 || len(header2.Number.Bytes()) > 32 { // block number should be less than 2^256
return nil, errInvalidEvidence
}
if header1.Number.Cmp(header2.Number) != 0 {
return nil, errInvalidEvidence
}
if header1.ParentHash != header2.ParentHash {
return nil, errInvalidEvidence
}
if len(header1.Extra) < extraSeal || len(header2.Extra) < extraSeal {
return nil, errInvalidEvidence
}
sig1 := header1.Extra[len(header1.Extra)-extraSeal:]
sig2 := header2.Extra[len(header2.Extra)-extraSeal:]
if bytes.Equal(sig1, sig2) {
return nil, errInvalidEvidence
}
// check sig
msgHash1 := types.SealHash(header1, evidence.ChainId)
msgHash2 := types.SealHash(header2, evidence.ChainId)
if bytes.Equal(msgHash1.Bytes(), msgHash2.Bytes()) {
return nil, errInvalidEvidence
}
pubkey1, err := secp256k1.RecoverPubkey(msgHash1.Bytes(), sig1)
if err != nil {
return nil, ErrExecutionReverted
}
pubkey2, err := secp256k1.RecoverPubkey(msgHash2.Bytes(), sig2)
if err != nil {
return nil, ErrExecutionReverted
}
if !bytes.Equal(pubkey1, pubkey2) {
return nil, errInvalidEvidence
}
returnBz := make([]byte, 52) // 20 + 32
signerAddr := crypto.Keccak256(pubkey1[1:])[12:]
evidenceHeightBz := header1.Number.Bytes()
copy(returnBz[:20], signerAddr)
copy(returnBz[52-len(evidenceHeightBz):], evidenceHeightBz)
return returnBz, nil
}

View File

@@ -8,8 +8,10 @@ import (
"github.com/tendermint/iavl"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/crypto/secp256k1"
cmn "github.com/tendermint/tendermint/libs/common"
//nolint:staticcheck
v1 "github.com/ethereum/go-ethereum/core/vm/lightclient/v1"
v2 "github.com/ethereum/go-ethereum/core/vm/lightclient/v2"
"github.com/ethereum/go-ethereum/params"
@@ -397,3 +399,40 @@ type cometBFTLightBlockValidateHertz struct {
func (c *cometBFTLightBlockValidateHertz) Run(input []byte) (result []byte, err error) {
return c.run(input, true)
}
// secp256k1SignatureRecover implemented as a native contract.
type secp256k1SignatureRecover struct{}
func (c *secp256k1SignatureRecover) RequiredGas(input []byte) uint64 {
return params.EcrecoverGas
}
const (
secp256k1PubKeyLength uint8 = 33
secp256k1SignatureLength uint8 = 64
secp256k1SignatureMsgHashLength uint8 = 32
)
// input:
// | PubKey | Signature | SignatureMsgHash |
// | 33 bytes | 64 bytes | 32 bytes |
func (c *secp256k1SignatureRecover) Run(input []byte) (result []byte, err error) {
if len(input) != int(secp256k1PubKeyLength)+int(secp256k1SignatureLength)+int(secp256k1SignatureMsgHashLength) {
return nil, fmt.Errorf("invalid input")
}
return c.runTMSecp256k1Signature(
input[:secp256k1PubKeyLength],
input[secp256k1PubKeyLength:secp256k1PubKeyLength+secp256k1SignatureLength],
input[secp256k1PubKeyLength+secp256k1SignatureLength:],
)
}
func (c *secp256k1SignatureRecover) runTMSecp256k1Signature(pubkey, signatureStr, msgHash []byte) (result []byte, err error) {
tmPubKey := secp256k1.PubKeySecp256k1(pubkey)
ok := tmPubKey.VerifyBytesWithMsgHash(msgHash, signatureStr)
if !ok {
return nil, fmt.Errorf("invalid signature")
}
return tmPubKey.Address().Bytes(), nil
}

View File

@@ -373,3 +373,42 @@ func TestCometBFTLightBlockValidateHertz(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expectOutputStr, hex.EncodeToString(res))
}
func TestSecp256k1SignatureRecover(t *testing.T) {
// local key
{
pubKey, err := hex.DecodeString("0278caa4d6321aa856d6341dd3e8bcdfe0b55901548871c63c3f5cec43c2ae88a9")
require.NoError(t, err)
sig, err := hex.DecodeString("0cb78be0d8eaeab991907b06c61240c04f4ca83f54b7799ce77cf029b837988038c4b3b7f5df231695b0d14499b716e1fd6504860eb3c9244ecb4e569d44c062")
require.NoError(t, err)
msghash, err := hex.DecodeString("b6ac827edff4bbbf23579720782dbef40b65780af292cc66849e7e5944f1230f")
require.NoError(t, err)
expectedAddr, err := hex.DecodeString("fa3B227adFf8EA1706098928715076D76959Ae6c")
require.NoError(t, err)
input := append(append(pubKey, sig...), msghash...)
contract := &secp256k1SignatureRecover{}
res, err := contract.Run(input)
require.NoError(t, err)
require.Equal(t, expectedAddr, res)
}
// ledger
{
pubKey, err := hex.DecodeString("02d63ee39adb1779353b4393dd5ea9d6d2b6df63b71d168571803cc7b9a0a20e98")
require.NoError(t, err)
sig, err := hex.DecodeString("66bdb5d381b2773c0f569858c7ee143959522d7c1f46dc656c325cb7353ec40c28ec22dff3650b34c096c5b12e702d7237d409f1ebaaa6dd1128a8f2d401fd5b")
require.NoError(t, err)
msghash, err := hex.DecodeString("c45e8f0dc7c054c31912beeffd6f10f1c585606d61e252e97968cd66661c2571")
require.NoError(t, err)
expectedAddr, err := hex.DecodeString("65a284146b84210a01add088954bb52d88b230af")
require.NoError(t, err)
input := append(append(pubKey, sig...), msghash...)
contract := &secp256k1SignatureRecover{}
res, err := contract.Run(input)
require.NoError(t, err)
require.Equal(t, expectedAddr, res)
}
}

View File

@@ -67,6 +67,7 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x0f, 0x11}): &bls12381MapG1{},
common.BytesToAddress([]byte{0x0f, 0x12}): &bls12381MapG2{},
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
common.BytesToAddress([]byte{104}): &verifyDoubleSignEvidence{},
}
// EIP-152 test vectors
@@ -405,3 +406,24 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
}
benchmarkPrecompiled("0f", testcase, b)
}
func TestDoubleSignSlash(t *testing.T) {
tc := precompiledTest{
Input: "f906278202cab9030ff9030ca01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0fae1a05fcb14bfd9b8a9f2b65007a9b6c2000de0627a73be644dd993d32342c494976ea74026e726554db657fa54763abd0c3a0aa9a0f385cc58ed297ff0d66eb5580b02853d3478ba418b1819ac659ee05df49b9794a0bf88464af369ed6b8cf02db00f0b9556ffa8d49cd491b00952a7f83431446638a00a6d0870e586a76278fbfdcedf76ef6679af18fc1f9137cfad495f434974ea81b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001820cdf830f4240830f4240846555fa64b90111d983010301846765746888676f312e32302e378664617277696e00007abd731ef8ae07b86091cb8836d58f5444b883422a18825d899035d3e6ea39ad1a50069bf0b86da8b5573dde1cb4a0a34f19ce94e0ef78ff7518c80265b8a3ca56e3c60167523590d4e8dcc324900559465fc0fa403774096614e135de280949b58a45cc96f2ba9e17f848820d41a08429d0d8b33ee72a84f750fefea846cbca54e487129c7961c680bb72309ca888820d42a08c9db14d938b19f9e2261bbeca2679945462be2b58103dfff73665d0d150fb8a804ae755e0fe64b59753f4db6308a1f679747bce186aa2c62b95fa6eeff3fbd08f3b0667e45428a54ade15bad19f49641c499b431b36f65803ea71b379e6b61de501a0232c9ba2d41b40d36ed794c306747bcbc49bf61a0f37409c18bfe2b5bef26a2d880000000000000000b9030ff9030ca01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0b2789a5357827ed838335283e15c4dcc42b9bebcbf2919a18613246787e2f96094976ea74026e726554db657fa54763abd0c3a0aa9a071ce4c09ee275206013f0063761bc19c93c13990582f918cc57333634c94ce89a00e095703e5c9b149f253fe89697230029e32484a410b4b1f2c61442d73c3095aa0d317ae19ede7c8a2d3ac9ef98735b049bcb7278d12f48c42b924538b60a25e12b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001820cdf830f4240830f4240846555fa64b90111d983010301846765746888676f312e32302e378664617277696e00007abd731ef8ae07b86091cb8836d58f5444b883422a18825d899035d3e6ea39ad1a50069bf0b86da8b5573dde1cb4a0a34f19ce94e0ef78ff7518c80265b8a3ca56e3c60167523590d4e8dcc324900559465fc0fa403774096614e135de280949b58a45cc96f2ba9e17f848820d41a08429d0d8b33ee72a84f750fefea846cbca54e487129c7961c680bb72309ca888820d42a08c9db14d938b19f9e2261bbeca2679945462be2b58103dfff73665d0d150fb8a80c0b17bfe88534296ff064cb7156548f6deba2d6310d5044ed6485f087dc6ef232e051c28e1909c2b50a3b4f29345d66681c319bef653e52e5d746480d5a3983b00a0b56228685be711834d0f154292d07826dea42a0fad3e4f56c31470b7fbfbea26880000000000000000",
Expected: "15d34aaf54267db7d7c367839aaf71a00a2c6a650000000000000000000000000000000000000000000000000000000000000cdf",
Gas: 10000,
Name: "",
}
testPrecompiled("68", tc, t)
}
func TestDoubleSignSlashFailure(t *testing.T) {
tc := precompiledFailureTest{
Input: "f9066b38b90332f9032fa01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0fae1a05fcb14bfd9b8a9f2b65007a9b6c2000de0627a73be644dd993d32342c494df87f0e2b8519ea2dd4abd8b639cdd628497ed25a0f385cc58ed297ff0d66eb5580b02853d3478ba418b1819ac659ee05df49b9794a0bf88464af369ed6b8cf02db00f0b9556ffa8d49cd491b00952a7f83431446638a00a6d0870e586a76278fbfdcedf76ef6679af18fc1f9137cfad495f434974ea81b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a1010000000000000000000000000000000000000000000000000000000000000000830f4240830f42408465bc6996b90115d983010306846765746889676f312e32302e3131856c696e7578000053474aa9f8b25fb860b0844a5082bfaa2299d2a23f076e2f6b17b15f839cc3e7d5a875656f6733fd4b87ba3401f906d15f3dea263cd9a6076107c7db620a4630dd3832c4a4b57eb8f497e28a3d69e5c03b30205c4b45675747d513e1accd66329770f3c35b18c9d023f84c84023a5ad6a086a28d985d9a6c8e7f9a4feadd5ace0adba9818e1e1727edca755fcc0bd8344684023a5ad7a0bc3492196b2e68b8e6ceea87cfa7588b4d590089eb885c4f2c1e9d9fb450f7b980988e1b9d0beb91dab063e04879a24c43d33baae3759dee41fd62ffa83c77fd202bea27a829b49e8025bdd198393526dd12b223ab16052fd26a43f3aabf63e76901a0232c9ba2d41b40d36ed794c306747bcbc49bf61a0f37409c18bfe2b5bef26a2d880000000000000000b90332f9032fa01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0b2789a5357827ed838335283e15c4dcc42b9bebcbf2919a18613246787e2f96094df87f0e2b8519ea2dd4abd8b639cdd628497ed25a071ce4c09ee275206013f0063761bc19c93c13990582f918cc57333634c94ce89a00e095703e5c9b149f253fe89697230029e32484a410b4b1f2c61442d73c3095aa0d317ae19ede7c8a2d3ac9ef98735b049bcb7278d12f48c42b924538b60a25e12b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a1010000000000000000000000000000000000000000000000000000000000000000830f4240830f42408465bc6996b90115d983010306846765746889676f312e32302e3131856c696e7578000053474aa9f8b25fb860b0844a5082bfaa2299d2a23f076e2f6b17b15f839cc3e7d5a875656f6733fd4b87ba3401f906d15f3dea263cd9a6076107c7db620a4630dd3832c4a4b57eb8f497e28a3d69e5c03b30205c4b45675747d513e1accd66329770f3c35b18c9d023f84c84023a5ad6a086a28d985d9a6c8e7f9a4feadd5ace0adba9818e1e1727edca755fcc0bd8344684023a5ad7a0bc3492196b2e68b8e6ceea87cfa7588b4d590089eb885c4f2c1e9d9fb450f7b9804c71ed015dd0c5c2d7393b68c2927f83f0a5da4c66f761f09e2f950cc610832c7876144599368404096ddef0eadacfde57717e2c7d23982b927285b797d41bfa00a0b56228685be711834d0f154292d07826dea42a0fad3e4f56c31470b7fbfbea26880000000000000000",
ExpectedError: errInvalidEvidence.Error(),
Name: "",
}
testPrecompiledFailure("68", tc, t)
}

View File

@@ -50,6 +50,8 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
switch {
case evm.chainRules.IsCancun:
precompiles = PrecompiledContractsCancun
case evm.chainRules.IsFeynman:
precompiles = PrecompiledContractsFeynman
case evm.chainRules.IsHertz:
precompiles = PrecompiledContractsHertz
case evm.chainRules.IsPlato:

View File

@@ -59,6 +59,7 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
if stateDb == nil {
return state.Dump{}, errors.New("pending state is not available")
}
opts.StateScheme = stateDb.Database().TrieDB().Scheme()
return stateDb.RawDump(opts), nil
}
var header *types.Header
@@ -83,6 +84,7 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
if err != nil {
return state.Dump{}, err
}
opts.StateScheme = stateDb.Database().TrieDB().Scheme()
return stateDb.RawDump(opts), nil
}
@@ -188,6 +190,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
OnlyWithAddresses: !incompletes,
Start: start,
Max: uint64(maxResults),
StateScheme: stateDb.Database().TrieDB().Scheme(),
}
if maxResults > AccountRangeMaxResults || maxResults <= 0 {
opts.Max = AccountRangeMaxResults

View File

@@ -189,6 +189,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
chainConfig.VerkleTime = config.OverrideVerkle
overrides.OverrideVerkle = config.OverrideVerkle
}
if config.OverrideFeynman != nil {
chainConfig.FeynmanTime = config.OverrideFeynman
overrides.OverrideFeynman = config.OverrideFeynman
}
if config.OverrideFeynmanFix != nil {
chainConfig.FeynmanFixTime = config.OverrideFeynmanFix
overrides.OverrideFeynmanFix = config.OverrideFeynmanFix
}
eth := &Ethereum{
config: config,

View File

@@ -197,6 +197,12 @@ type Config struct {
// OverrideVerkle (TODO: remove after the fork)
OverrideVerkle *uint64 `toml:",omitempty"`
// OverrideFeynman (TODO: remove after the fork)
OverrideFeynman *uint64 `toml:",omitempty"`
// OverrideFeynmanFix (TODO: remove after the fork)
OverrideFeynmanFix *uint64 `toml:",omitempty"`
}
// CreateConsensusEngine creates a consensus engine for the given chain config.

View File

@@ -338,7 +338,7 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool)
// If 'other reject' is >25% of the deliveries in any batch, sleep a bit.
if otherreject > 128/4 {
time.Sleep(200 * time.Millisecond)
log.Warn("Peer delivering stale transactions", "peer", peer, "rejected", otherreject)
log.Debug("Peer delivering stale transactions", "peer", peer, "rejected", otherreject)
}
}
select {

View File

@@ -227,8 +227,8 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL
if p < 0 || p > 100 {
return common.Big0, nil, nil, nil, fmt.Errorf("%w: %f", errInvalidPercentile, p)
}
if i > 0 && p < rewardPercentiles[i-1] {
return common.Big0, nil, nil, nil, fmt.Errorf("%w: #%d:%f > #%d:%f", errInvalidPercentile, i-1, rewardPercentiles[i-1], i, p)
if i > 0 && p <= rewardPercentiles[i-1] {
return common.Big0, nil, nil, nil, fmt.Errorf("%w: #%d:%f >= #%d:%f", errInvalidPercentile, i-1, rewardPercentiles[i-1], i, p)
}
}
var (

View File

@@ -381,8 +381,6 @@ func (h *handler) protoTracker() {
<-h.handlerDoneCh
}
return
case <-h.stopCh:
return
}
}
}

View File

@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/systemcontracts"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
@@ -239,12 +240,37 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
if err != nil {
return nil, vm.BlockContext{}, nil, nil, err
}
// upgrade build-in system contract before normal txs if Feynman is not enabled
if !eth.blockchain.Config().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb)
}
if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.BlockContext{}, statedb, release, nil
}
// Recompute transactions up to the target index.
signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time())
var (
signer = types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time())
beforeSystemTx = true
)
for idx, tx := range block.Transactions() {
// upgrade build-in system contract before system txs if Feynman is enabled
if beforeSystemTx {
if posa, ok := eth.Engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem {
balance := statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(block.Header().Coinbase, balance)
}
if eth.blockchain.Config().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb)
}
beforeSystemTx = false
}
}
}
// Assemble the transaction call message and return if the requested offset
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
txContext := core.NewEVMTxContext(msg)
@@ -254,14 +280,6 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
}
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
if posa, ok := eth.Engine().(consensus.PoSA); ok && msg.From == context.Coinbase &&
posa.IsSystemContract(msg.To) && msg.GasPrice.Cmp(big.NewInt(0)) == 0 {
balance := statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(context.Coinbase, balance)
}
}
statedb.SetTxContext(tx.Hash(), idx)
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)

View File

@@ -132,8 +132,6 @@ func (cs *chainSyncer) loop() {
<-cs.doneCh
}
return
case <-cs.handler.stopCh:
return
}
}
}

View File

@@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/systemcontracts"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
@@ -187,6 +188,7 @@ type txTraceResult struct {
// being traced.
type blockTraceTask struct {
statedb *state.StateDB // Intermediate state prepped for tracing
parent *types.Block // Parent block of the trace block
block *types.Block // Block to trace the transactions from
release StateReleaseFunc // The function to release the held resource for this task
results []*txTraceResult // Trace results produced by the task
@@ -205,6 +207,7 @@ type blockTraceResult struct {
type txTraceTask struct {
statedb *state.StateDB // Intermediate state prepped for tracing
index int // Transaction offset in the block
isSystemTx bool // Whether the transaction is a system transaction
}
// TraceChain returns the structured logs created during the execution of EVM
@@ -269,9 +272,28 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
var (
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
beforeSystemTx = true
)
// Trace all the transactions contained within
for i, tx := range task.block.Transactions() {
// upgrade build-in system contract before system txs if Feynman is enabled
if beforeSystemTx {
if posa, ok := api.backend.Engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(tx, task.block.Header()); isSystem {
balance := task.statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
task.statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
task.statedb.AddBalance(blockCtx.Coinbase, balance)
}
if api.backend.ChainConfig().IsFeynman(task.block.Number(), task.block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), task.block.Number(), task.parent.Time(), task.block.Time(), task.statedb)
}
beforeSystemTx = false
}
}
}
msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
txctx := &Context{
BlockHash: task.block.Hash(),
@@ -279,7 +301,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, !beforeSystemTx)
if err != nil {
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
@@ -386,10 +408,15 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// may fail if we release too early.
tracker.callReleases()
// upgrade build-in system contract before normal txs if Feynman is not enabled
if !api.backend.ChainConfig().IsFeynman(next.Number(), next.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), next.Number(), block.Time(), next.Time(), statedb)
}
// Send the block over to the concurrent tracers (if not in the fast-forward phase)
txs := next.Transactions()
select {
case taskCh <- &blockTraceTask{statedb: statedb.Copy(), block: next, release: release, results: make([]*txTraceResult, len(txs))}:
case taskCh <- &blockTraceTask{statedb: statedb.Copy(), parent: block, block: next, release: release, results: make([]*txTraceResult, len(txs))}:
case <-closed:
tracker.releaseState(number, release)
return
@@ -522,12 +549,18 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
}
defer release()
// upgrade build-in system contract before normal txs if Feynman is not enabled
if !api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb)
}
var (
roots []common.Hash
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
chainConfig = api.backend.ChainConfig()
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
beforeSystemTx = true
)
for i, tx := range block.Transactions() {
if err := ctx.Err(); err != nil {
@@ -546,6 +579,11 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(vmctx.Coinbase, balance)
}
if beforeSystemTx && api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb)
beforeSystemTx = false
}
}
}
@@ -602,6 +640,11 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
}
defer release()
// upgrade build-in system contract before normal txs if Feynman is not enabled
if !api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb)
}
// JS tracers have high overhead. In this case run a parallel
// process that generates states in one thread and traces txes
// in separate worker threads.
@@ -610,6 +653,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
return api.traceBlockParallel(ctx, block, statedb, config)
}
}
// Native tracers have low overhead
var (
txs = block.Transactions()
@@ -618,8 +662,27 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
results = make([]*txTraceResult, len(txs))
beforeSystemTx = true
)
for i, tx := range txs {
// upgrade build-in system contract before system txs if Feynman is enabled
if beforeSystemTx {
if posa, ok := api.backend.Engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem {
balance := statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(blockCtx.Coinbase, balance)
}
if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb)
}
beforeSystemTx = false
}
}
}
// Generate the next state snapshot fast without tracing
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
txctx := &Context{
@@ -628,7 +691,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config)
res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config, !beforeSystemTx)
if err != nil {
return nil, err
}
@@ -672,7 +735,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
TxIndex: task.index,
TxHash: txs[task.index].Hash(),
}
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, task.isSystemTx)
if err != nil {
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
continue
@@ -682,12 +745,38 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
})
}
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
if err != nil {
return nil, err
}
// Feed the transactions into the tracers and return
var failed error
var (
failed error
beforeSystemTx = true
)
txloop:
for i, tx := range txs {
// upgrade build-in system contract before system txs if Feynman is enabled
if beforeSystemTx {
if posa, ok := api.backend.Engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem {
balance := statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(block.Header().Coinbase, balance)
}
if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb)
}
beforeSystemTx = false
}
}
}
// Send the trace task over for execution
task := &txTraceTask{statedb: statedb.Copy(), index: i}
task := &txTraceTask{statedb: statedb.Copy(), index: i, isSystemTx: !beforeSystemTx}
select {
case <-ctx.Done():
failed = ctx.Err()
@@ -697,15 +786,6 @@ txloop:
// Generate the next state snapshot fast without tracing
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
if posa, ok := api.backend.Engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem {
balance := statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(block.Header().Coinbase, balance)
}
}
}
statedb.SetTxContext(tx.Hash(), i)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
@@ -754,6 +834,11 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
}
defer release()
// upgrade build-in system contract before normal txs if Feynman is not enabled
if !api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb)
}
// Retrieve the tracing configurations, or use default values
var (
logConfig logger.Config
@@ -772,6 +857,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
chainConfig = api.backend.ChainConfig()
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
canon = true
beforeSystemTx = true
)
// Check if there are any overrides: the caller may wish to enable a future
// fork when executing this block. Note, such overrides are only applicable to the
@@ -782,7 +868,26 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// Note: This copies the config, to not screw up the main config
chainConfig, canon = overrideConfig(chainConfig, config.Overrides)
}
for i, tx := range block.Transactions() {
// upgrade build-in system contract before system txs if Feynman is enabled
if beforeSystemTx {
if posa, ok := api.backend.Engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem {
balance := statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(vmctx.Coinbase, balance)
}
if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb)
}
beforeSystemTx = false
}
}
}
// Prepare the transaction for un-traced execution
var (
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
@@ -814,15 +919,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
}
// Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
if posa, ok := api.backend.Engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem {
balance := statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(vmctx.Coinbase, balance)
}
}
}
statedb.SetTxContext(tx.Hash(), i)
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
if writer != nil {
@@ -887,13 +983,20 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
}
defer release()
var isSystemTx bool
if posa, ok := api.backend.Engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem {
isSystemTx = true
}
}
txctx := &Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
TxIndex: int(index),
TxHash: hash,
}
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config, isSystemTx)
}
// TraceCall lets you trace a given eth_call. It collects the structured logs
@@ -934,6 +1037,17 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
}
defer release()
// upgrade build-in system contract before tracing if Feynman is not enabled
if block.NumberU64() > 0 {
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
if err != nil {
return nil, err
}
if !api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) {
systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb)
}
}
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
// Apply the customization rules if required.
if config != nil {
@@ -952,13 +1066,13 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
if config != nil {
traceConfig = &config.TraceConfig
}
return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig, false)
}
// traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will
// be tracer dependent.
func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig, isSystemTx bool) (interface{}, error) {
var (
tracer Tracer
err error
@@ -997,13 +1111,7 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte
var intrinsicGas uint64 = 0
// Run the transaction with tracing enabled.
if posa, ok := api.backend.Engine().(consensus.PoSA); ok && message.From == vmctx.Coinbase &&
posa.IsSystemContract(message.To) && message.GasPrice.Cmp(big.NewInt(0)) == 0 {
balance := statedb.GetBalance(consensus.SystemAddress)
if balance.Cmp(common.Big0) > 0 {
statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
statedb.AddBalance(vmctx.Coinbase, balance)
}
if isSystemTx {
intrinsicGas, _ = core.IntrinsicGas(message.Data, message.AccessList, false, true, true, false)
}

4
go.mod
View File

@@ -234,7 +234,7 @@ require (
github.com/prysmaticlabs/prysm v0.0.0-20220124113610-e26cde5e091b // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
github.com/quic-go/quic-go v0.39.3 // indirect
github.com/quic-go/quic-go v0.39.4 // indirect
github.com/quic-go/webtransport-go v0.6.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
@@ -293,5 +293,5 @@ replace (
github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-tendermint v0.0.0-20230417032003-4cda1f296fb2
github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1
github.com/syndtr/goleveldb v1.0.1 => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.15
github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.16
)

8
go.sum
View File

@@ -193,8 +193,8 @@ github.com/bnb-chain/greenfield-tendermint v0.0.0-20230417032003-4cda1f296fb2 h1
github.com/bnb-chain/greenfield-tendermint v0.0.0-20230417032003-4cda1f296fb2/go.mod h1:9q11eHNRY9FDwFH+4pompzPNGv//Z3VcfvkELaHJPMs=
github.com/bnb-chain/ics23 v0.1.0 h1:DvjGOts2FBfbxB48384CYD1LbcrfjThFz8kowY/7KxU=
github.com/bnb-chain/ics23 v0.1.0/go.mod h1:cU6lTGolbbLFsGCgceNB2AzplH1xecLp6+KXvxM32nI=
github.com/bnb-chain/tendermint v0.31.15 h1:Xyn/Hifb/7X4E1zSuMdnZdMSoM2Fx6cZuKCNnqIxbNU=
github.com/bnb-chain/tendermint v0.31.15/go.mod h1:cmt8HHmQUSVaWQ/hoTefRxsh5X3ERaM1zCUIR0DPbFU=
github.com/bnb-chain/tendermint v0.31.16 h1:rOO6WG61JDAuRCCL8TKnGhorJftQDVygq0mqR7A0ck4=
github.com/bnb-chain/tendermint v0.31.16/go.mod h1:cmt8HHmQUSVaWQ/hoTefRxsh5X3ERaM1zCUIR0DPbFU=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
@@ -1434,8 +1434,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.39.3 h1:o3YB6t2SR+HU/pgwF29kJ6g4jJIJEwEZ8CKia1h1TKg=
github.com/quic-go/quic-go v0.39.3/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
github.com/quic-go/quic-go v0.39.4 h1:PelfiuG7wXEffUT2yceiqz5V6Pc0TA5ruOd1LcmFc1s=
github.com/quic-go/quic-go v0.39.4/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc/go.mod h1:S8xSOnV3CgpNrWd0GQ/OoQfMtlg2uPRSuTzcSGrzwK8=

View File

@@ -10,6 +10,8 @@ import (
"time"
)
const backupTimeFormat = "2006-01-02_15"
type TimeTicker struct {
stop chan struct{}
C <-chan time.Time
@@ -69,9 +71,12 @@ type AsyncFileWriter struct {
buf chan []byte
stop chan struct{}
timeTicker *TimeTicker
rotateHours uint
maxBackups int
}
func NewAsyncFileWriter(filePath string, maxBytesSize int64, rotateHours uint) *AsyncFileWriter {
func NewAsyncFileWriter(filePath string, maxBytesSize int64, maxBackups int, rotateHours uint) *AsyncFileWriter {
absFilePath, err := filepath.Abs(filePath)
if err != nil {
panic(fmt.Sprintf("get file path of logger error. filePath=%s, err=%s", filePath, err))
@@ -81,6 +86,8 @@ func NewAsyncFileWriter(filePath string, maxBytesSize int64, rotateHours uint) *
filePath: absFilePath,
buf: make(chan []byte, maxBytesSize),
stop: make(chan struct{}),
rotateHours: rotateHours,
maxBackups: maxBackups,
timeTicker: NewTimeTicker(rotateHours),
}
}
@@ -178,6 +185,9 @@ func (w *AsyncFileWriter) rotateFile() {
if err := w.initLogFile(); err != nil {
fmt.Fprintf(os.Stderr, "init log file error. err=%s", err)
}
if err := w.removeExpiredFile(); err != nil {
fmt.Fprintf(os.Stderr, "remove expired file error. err=%s", err)
}
default:
}
}
@@ -222,5 +232,29 @@ func (w *AsyncFileWriter) flushAndClose() error {
}
func (w *AsyncFileWriter) timeFilePath(filePath string) string {
return filePath + "." + time.Now().Format("2006-01-02_15")
return filePath + "." + time.Now().Format(backupTimeFormat)
}
func (w *AsyncFileWriter) getExpiredFile(filePath string, maxBackups int, rotateHours uint) string {
if rotateHours > 0 {
maxBackups = int(rotateHours) * maxBackups
}
return filePath + "." + time.Now().Add(-time.Hour*time.Duration(maxBackups)).Format(backupTimeFormat)
}
func (w *AsyncFileWriter) removeExpiredFile() error {
if w.maxBackups == 0 {
return nil
}
oldFilepath := w.getExpiredFile(w.filePath, w.maxBackups, w.rotateHours)
_, err := os.Stat(oldFilepath)
if os.IsNotExist(err) {
return nil
}
errRemove := os.Remove(oldFilepath)
if err != nil {
return errRemove
}
return err
}

View File

@@ -6,10 +6,12 @@ import (
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestWriterHourly(t *testing.T) {
w := NewAsyncFileWriter("./hello.log", 100, 1)
w := NewAsyncFileWriter("./hello.log", 100, 1, 1)
w.Start()
w.Write([]byte("hello\n"))
w.Write([]byte("world\n"))
@@ -67,3 +69,22 @@ func TestGetNextRotationHour(t *testing.T) {
t.Run("TestGetNextRotationHour_"+strconv.Itoa(i), test(tc.now, tc.delta, tc.expectedHour))
}
}
func TestClearBackups(t *testing.T) {
dir := "./test"
os.Mkdir(dir, 0700)
w := NewAsyncFileWriter("./test/bsc.log", 100, 1, 1)
defer os.RemoveAll(dir)
fakeCurrentTime := time.Now()
name := ""
data := []byte("data")
for i := 0; i < 5; i++ {
name = w.filePath + "." + fakeCurrentTime.Format(backupTimeFormat)
_ = os.WriteFile(name, data, 0700)
fakeCurrentTime = fakeCurrentTime.Add(-time.Hour * 1)
}
oldFile := w.getExpiredFile(w.filePath, w.maxBackups, w.rotateHours)
w.removeExpiredFile()
_, err := os.Stat(oldFile)
assert.True(t, os.IsNotExist(err))
}

View File

@@ -75,14 +75,14 @@ func FileHandler(path string, fmtr Format) (Handler, error) {
// RotatingFileHandler returns a handler which writes log records to file chunks
// at the given path. When a file's size reaches the limit, the handler creates
// a new file named after the timestamp of the first log record it will contain.
func RotatingFileHandler(filePath string, limit uint, formatter Format, rotateHours uint) (Handler, error) {
func RotatingFileHandler(filePath string, limit uint, maxBackups uint, formatter Format, rotateHours uint) (Handler, error) {
if _, err := os.Stat(path.Dir(filePath)); os.IsNotExist(err) {
err := os.MkdirAll(path.Dir(filePath), 0755)
if err != nil {
return nil, fmt.Errorf("could not create directory %s, %v", path.Dir(filePath), err)
}
}
fileWriter := NewAsyncFileWriter(filePath, int64(limit), rotateHours)
fileWriter := NewAsyncFileWriter(filePath, int64(limit), int(maxBackups), rotateHours)
fileWriter.Start()
return StreamHandler(fileWriter, formatter), nil
}

View File

@@ -290,8 +290,8 @@ func (c Ctx) toArray() []interface{} {
return arr
}
func NewFileLvlHandler(logPath string, maxBytesSize uint, level string, rotateHours uint) Handler {
rfh, err := RotatingFileHandler(logPath, maxBytesSize, LogfmtFormat(), rotateHours)
func NewFileLvlHandler(logPath string, maxBytesSize uint, maxBackups uint, level string, rotateHours uint) Handler {
rfh, err := RotatingFileHandler(logPath, maxBytesSize, maxBackups, LogfmtFormat(), rotateHours)
if err != nil {
panic(err)
}

View File

@@ -909,8 +909,10 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
return nil, err
}
if !w.chainConfig.IsFeynman(header.Number, header.Time) {
// Handle upgrade build-in system contract code
systemcontracts.UpgradeBuildInSystemContract(w.chainConfig, header.Number, parent.Time, header.Time, env.state)
}
return env, nil
}

View File

@@ -513,6 +513,7 @@ type LogConfig struct {
MaxBytesSize *uint `toml:",omitempty"`
Level *string `toml:",omitempty"`
RotateHours *uint `toml:",omitempty"`
MaxBackups *uint `toml:",omitempty"`
// TermTimeFormat is the time format used for console logging.
TermTimeFormat *string `toml:",omitempty"`

View File

@@ -118,7 +118,12 @@ func New(conf *Config) (*Node, error) {
rotateHours = *conf.LogConfig.RotateHours
}
log.Root().SetHandler(log.NewFileLvlHandler(logFilePath, *conf.LogConfig.MaxBytesSize, *conf.LogConfig.Level, rotateHours))
maxBackups := uint(0)
if conf.LogConfig.MaxBackups != nil {
maxBackups = *conf.LogConfig.MaxBackups
}
log.Root().SetHandler(log.NewFileLvlHandler(logFilePath, *conf.LogConfig.MaxBytesSize, maxBackups, *conf.LogConfig.Level, rotateHours))
}
}
if conf.Logger == nil {

View File

@@ -65,9 +65,6 @@ const (
// Maximum amount of time allowed for writing a complete message.
frameWriteTimeout = 20 * time.Second
// Maximum time to wait before stop the p2p server
stopTimeout = 5 * time.Second
)
var (
@@ -457,7 +454,7 @@ func (srv *Server) Stop() {
select {
case <-stopChan:
case <-time.After(stopTimeout):
case <-time.After(defaultDialTimeout): // we should use defaultDialTimeout as we can dial just before the shutdown
srv.log.Warn("stop p2p server timeout, forcing stop")
}
}

View File

@@ -223,8 +223,8 @@ func TestServerStopTimeout(t *testing.T) {
select {
case <-stopChan:
case <-time.After(10 * time.Second):
t.Error("server should be shutdown in 10 seconds")
case <-time.After(defaultDialTimeout + 1*time.Second):
t.Error("server should be shutdown in defaultDialTimeout + 1 seconds")
}
}

View File

@@ -148,6 +148,9 @@ var (
ShanghaiTime: newUint64(1705996800),
KeplerTime: newUint64(1705996800),
// TODO
FeynmanTime: nil,
Parlia: &ParliaConfig{
Period: 3,
Epoch: 200,
@@ -183,6 +186,10 @@ var (
// UnixTime: 1702972800 is December 19, 2023 8:00:00 AM UTC
ShanghaiTime: newUint64(1702972800),
KeplerTime: newUint64(1702972800),
FeynmanTime: newUint64(1710136800),
// TODO
FeynmanFixTime: nil,
Parlia: &ParliaConfig{
Period: 3,
@@ -219,10 +226,12 @@ var (
HertzfixBlock: big.NewInt(8),
ShanghaiTime: newUint64(0),
KeplerTime: newUint64(0),
FeynmanTime: _rialto_upgrade_height_,
FeynmanFixTime: _rialto_upgrade_height_,
Parlia: &ParliaConfig{
Period: 3,
Epoch: 200,
Period: _rialto_parlia_period_,
Epoch: _rialto_parlia_epoch_,
},
}
@@ -456,6 +465,8 @@ type ChainConfig struct {
ShanghaiTime *uint64 `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai)
KeplerTime *uint64 `json:"keplerTime,omitempty"` // Kepler switch time (nil = no fork, 0 = already activated)
FeynmanTime *uint64 `json:"feynmanTime,omitempty"` // Feynman switch time (nil = no fork, 0 = already activated)
FeynmanFixTime *uint64 `json:"feynmanFixTime,omitempty"` // Feynman switch time (nil = no fork, 0 = already activated)
CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun)
PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
@@ -548,7 +559,17 @@ func (c *ChainConfig) String() string {
KeplerTime = big.NewInt(0).SetUint64(*c.KeplerTime)
}
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, CatalystBlock: %v, London: %v, ArrowGlacier: %v, MergeFork:%v, Euler: %v, Gibbs: %v, Nano: %v, Moran: %v, Planck: %v,Luban: %v, Plato: %v, Hertz: %v, Hertzfix: %v, ShanghaiTime: %v, KeplerTime: %v, Engine: %v}",
var FeynmanTime *big.Int
if c.FeynmanTime != nil {
FeynmanTime = big.NewInt(0).SetUint64(*c.FeynmanTime)
}
var FeynmanFixTime *big.Int
if c.FeynmanFixTime != nil {
FeynmanFixTime = big.NewInt(0).SetUint64(*c.FeynmanFixTime)
}
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, CatalystBlock: %v, London: %v, ArrowGlacier: %v, MergeFork:%v, Euler: %v, Gibbs: %v, Nano: %v, Moran: %v, Planck: %v,Luban: %v, Plato: %v, Hertz: %v, Hertzfix: %v, ShanghaiTime: %v, KeplerTime: %v, FeynmanTime: %v, FeynmanFixTime: %v, Engine: %v}",
c.ChainID,
c.HomesteadBlock,
c.DAOForkBlock,
@@ -582,6 +603,8 @@ func (c *ChainConfig) String() string {
c.HertzfixBlock,
ShanghaiTime,
KeplerTime,
FeynmanTime,
FeynmanFixTime,
engine,
)
}
@@ -816,6 +839,34 @@ func (c *ChainConfig) IsOnKepler(currentBlockNumber *big.Int, lastBlockTime uint
return !c.IsKepler(lastBlockNumber, lastBlockTime) && c.IsKepler(currentBlockNumber, currentBlockTime)
}
// IsFeynman returns whether time is either equal to the Feynman fork time or greater.
func (c *ChainConfig) IsFeynman(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.FeynmanTime, time)
}
// IsOnFeynman returns whether currentBlockTime is either equal to the Feynman fork time or greater firstly.
func (c *ChainConfig) IsOnFeynman(currentBlockNumber *big.Int, lastBlockTime uint64, currentBlockTime uint64) bool {
lastBlockNumber := new(big.Int)
if currentBlockNumber.Cmp(big.NewInt(1)) >= 0 {
lastBlockNumber.Sub(currentBlockNumber, big.NewInt(1))
}
return !c.IsFeynman(lastBlockNumber, lastBlockTime) && c.IsFeynman(currentBlockNumber, currentBlockTime)
}
// IsFeynmanFix returns whether time is either equal to the FeynmanFix fork time or greater.
func (c *ChainConfig) IsFeynmanFix(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.FeynmanFixTime, time)
}
// IsOnFeynmanFix returns whether currentBlockTime is either equal to the FeynmanFix fork time or greater firstly.
func (c *ChainConfig) IsOnFeynmanFix(currentBlockNumber *big.Int, lastBlockTime uint64, currentBlockTime uint64) bool {
lastBlockNumber := new(big.Int)
if currentBlockNumber.Cmp(big.NewInt(1)) >= 0 {
lastBlockNumber.Sub(currentBlockNumber, big.NewInt(1))
}
return !c.IsFeynmanFix(lastBlockNumber, lastBlockTime) && c.IsFeynmanFix(currentBlockNumber, currentBlockTime)
}
// IsCancun returns whether num is either equal to the Cancun fork time or greater.
func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.CancunTime, time)
@@ -881,6 +932,8 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
{name: "hertzBlock", block: c.HertzBlock},
{name: "hertzfixBlock", block: c.HertzfixBlock},
{name: "keplerTime", timestamp: c.KeplerTime},
{name: "feynmanTime", timestamp: c.FeynmanTime},
{name: "feynmanFixTime", timestamp: c.FeynmanFixTime},
{name: "cancunTime", timestamp: c.CancunTime, optional: true},
{name: "pragueTime", timestamp: c.PragueTime, optional: true},
{name: "verkleTime", timestamp: c.VerkleTime, optional: true},
@@ -1020,6 +1073,12 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int,
if isForkTimestampIncompatible(c.KeplerTime, newcfg.KeplerTime, headTimestamp) {
return newTimestampCompatError("Kepler fork timestamp", c.KeplerTime, newcfg.KeplerTime)
}
if isForkTimestampIncompatible(c.FeynmanTime, newcfg.FeynmanTime, headTimestamp) {
return newTimestampCompatError("Feynman fork timestamp", c.FeynmanTime, newcfg.FeynmanTime)
}
if isForkTimestampIncompatible(c.FeynmanFixTime, newcfg.FeynmanFixTime, headTimestamp) {
return newTimestampCompatError("FeynmanFix fork timestamp", c.FeynmanFixTime, newcfg.FeynmanFixTime)
}
if isForkTimestampIncompatible(c.CancunTime, newcfg.CancunTime, headTimestamp) {
return newTimestampCompatError("Cancun fork timestamp", c.CancunTime, newcfg.CancunTime)
}
@@ -1181,7 +1240,7 @@ type Rules struct {
IsPlato bool
IsHertz bool
IsHertzfix bool
IsShanghai, IsKepler, IsCancun, IsPrague bool
IsShanghai, IsKepler, IsFeynman, IsCancun, IsPrague bool
IsVerkle bool
}
@@ -1213,6 +1272,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
IsHertzfix: c.IsHertzfix(num),
IsShanghai: c.IsShanghai(num, timestamp),
IsKepler: c.IsKepler(num, timestamp),
IsFeynman: c.IsFeynman(num, timestamp),
IsCancun: c.IsCancun(num, timestamp),
IsPrague: c.IsPrague(num, timestamp),
IsVerkle: c.IsVerkle(num, timestamp),

View File

@@ -31,7 +31,7 @@ const (
CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero.
CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
SystemTxsGas uint64 = 5000000 // The gas reserved for system txs; only for parlia consensus
SystemTxsGas uint64 = 20000000 // The gas reserved for system txs; only for parlia consensus
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
@@ -144,6 +144,7 @@ const (
IdentityPerWordGas uint64 = 3 // Per-work price for a data copy operation
BlsSignatureVerifyBaseGas uint64 = 1000 // base price for a BLS signature verify operation
BlsSignatureVerifyPerKeyGas uint64 = 3500 // Per-key price for a BLS signature verify operation
DoubleSignEvidenceVerifyGas uint64 = 10000 // Gas for verify double sign evidence
Bn256AddGasByzantium uint64 = 500 // Byzantium gas needed for an elliptic curve addition
Bn256AddGasIstanbul uint64 = 150 // Gas needed for an elliptic curve addition

View File

@@ -23,7 +23,7 @@ import (
const (
VersionMajor = 1 // Major version component of the current release
VersionMinor = 3 // Minor version component of the current release
VersionPatch = 8 // Patch version component of the current release
VersionPatch = 10 // Patch version component of the current release
VersionMeta = "" // Version metadata to append to the version string
)

View File

@@ -262,7 +262,7 @@ func parliaHeaderHashAndRlp(header *types.Header, chainId *big.Int) (hash, rlp [
return
}
rlp = parlia.ParliaRLP(header, chainId)
hash = parlia.SealHash(header, chainId).Bytes()
hash = types.SealHash(header, chainId).Bytes()
return hash, rlp, err
}

View File

@@ -355,7 +355,7 @@ func (db *Database) SetBufferSize(size int) error {
}
// Head return the top non-fork difflayer/disklayer root hash for rewinding.
// It's only supported by path-based database and will return an error for
// It's only supported by path-based database and will return empty hash for
// others.
func (db *Database) Head() common.Hash {
pdb, ok := db.backend.(*pathdb.Database)
@@ -364,3 +364,15 @@ func (db *Database) Head() common.Hash {
}
return pdb.Head()
}
// GetAllHash returns all MPT root hash in diffLayer and diskLayer.
// It's only supported by path-based database and will return nil for
// others.
func (db *Database) GetAllRooHash() [][]string {
pdb, ok := db.backend.(*pathdb.Database)
if !ok {
log.Error("Not supported")
return nil
}
return pdb.GetAllRooHash()
}

View File

@@ -226,7 +226,7 @@ func (nc *nodecache) node(owner common.Hash, path []byte, hash common.Hash) (*tr
}
if n.Hash != hash {
dirtyFalseMeter.Mark(1)
log.Error("Unexpected trie node in node buffer", "owner", owner, "path", path, "expect", hash, "got", n.Hash)
log.Error("Unexpected trie node in async node buffer", "owner", owner, "path", path, "expect", hash, "got", n.Hash)
return nil, newUnexpectedNodeError("dirty", hash, n.Hash, owner, path, n.Blob)
}
return n, nil

View File

@@ -20,6 +20,8 @@ import (
"errors"
"fmt"
"io"
"sort"
"strconv"
"sync"
"time"
@@ -441,3 +443,24 @@ func (db *Database) Head() common.Hash {
defer db.lock.Unlock()
return db.tree.front()
}
// GetAllRooHash returns all diffLayer and diskLayer root hash
func (db *Database) GetAllRooHash() [][]string {
db.lock.Lock()
defer db.lock.Unlock()
data := make([][]string, 0, len(db.tree.layers))
for _, v := range db.tree.layers {
if dl, ok := v.(*diffLayer); ok {
data = append(data, []string{fmt.Sprintf("%d", dl.block), dl.rootHash().String()})
}
}
sort.Slice(data, func(i, j int) bool {
block1, _ := strconv.Atoi(data[i][0])
block2, _ := strconv.Atoi(data[j][0])
return block1 > block2
})
data = append(data, []string{"-1", db.tree.bottom().rootHash().String()})
return data
}