Compare commits
21 Commits
v1.3.8
...
fix-v1.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05c1f1438c | ||
|
|
4b5eebead1 | ||
|
|
b5603d2e98 | ||
|
|
c8cc91963f | ||
|
|
bd13416162 | ||
|
|
b7b64da564 | ||
|
|
73f27a590f | ||
|
|
5e74ea650d | ||
|
|
5378df3702 | ||
|
|
40cae45436 | ||
|
|
361e8413e6 | ||
|
|
36a283ef98 | ||
|
|
78d1cade19 | ||
|
|
82beb2c5f3 | ||
|
|
3761bf0426 | ||
|
|
29427c51fd | ||
|
|
220be95117 | ||
|
|
f0d9f61bf6 | ||
|
|
d49da4348c | ||
|
|
fecd2bfafe | ||
|
|
ef13f3194d |
4
.github/workflows/build-test.yml
vendored
4
.github/workflows/build-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
@@ -47,5 +47,3 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
go mod download
|
go mod download
|
||||||
make geth
|
make geth
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/commit-lint.yml
vendored
2
.github/workflows/commit-lint.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/integration-test.yml
vendored
2
.github/workflows/integration-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
${{ runner.os }}-go-
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
- run: |
|
- run: |
|
||||||
go mod download
|
go mod tidy
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v3
|
||||||
|
|||||||
37
.github/workflows/nancy.yml
vendored
Normal file
37
.github/workflows/nancy.yml
vendored
Normal 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
|
||||||
3
.github/workflows/unit-test.yml
vendored
3
.github/workflows/unit-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
@@ -51,4 +51,3 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
go mod download
|
go mod download
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
|||||||
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,4 +1,26 @@
|
|||||||
# Changelog
|
# 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
|
## v1.3.8
|
||||||
FEATURE
|
FEATURE
|
||||||
* [\#2074](https://github.com/bnb-chain/bsc/pull/2074) faucet: new faucet client
|
* [\#2074](https://github.com/bnb-chain/bsc/pull/2074) faucet: new faucet client
|
||||||
|
|||||||
@@ -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)
|
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
|
replacer.Dir = pkg
|
||||||
if out, err := replacer.CombinedOutput(); err != nil {
|
if out, err := replacer.CombinedOutput(); err != nil {
|
||||||
t.Fatalf("failed to replace tendermint dependency to bnb-chain source: %v\n%s", err, out)
|
t.Fatalf("failed to replace tendermint dependency to bnb-chain source: %v\n%s", err, out)
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ func doLint(cmdline []string) {
|
|||||||
|
|
||||||
// downloadLinter downloads and unpacks golangci-lint.
|
// downloadLinter downloads and unpacks golangci-lint.
|
||||||
func downloadLinter(cachedir string) string {
|
func downloadLinter(cachedir string) string {
|
||||||
const version = "1.52.2"
|
const version = "1.55.2"
|
||||||
|
|
||||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
arch := runtime.GOARCH
|
arch := runtime.GOARCH
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -14,6 +15,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
|
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
|
||||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||||
"github.com/prysmaticlabs/prysm/v4/io/prompt"
|
"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"
|
||||||
"github.com/prysmaticlabs/prysm/v4/validator/accounts/iface"
|
"github.com/prysmaticlabs/prysm/v4/validator/accounts/iface"
|
||||||
"github.com/prysmaticlabs/prysm/v4/validator/accounts/petnames"
|
"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/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/ethereum/go-ethereum/signer/core"
|
"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",
|
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,
|
Category: flags.AccountCategory,
|
||||||
}
|
}
|
||||||
|
chainIdFlag = &cli.Int64Flag{
|
||||||
|
Name: "chain-id",
|
||||||
|
Usage: "The chain id of the network that the validator will be created at",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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.`,
|
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
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/olekukonko/tablewriter"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
@@ -44,7 +47,8 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"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 (
|
var (
|
||||||
@@ -191,6 +195,21 @@ It's deprecated, please use "geth db export" instead.
|
|||||||
}, utils.DatabasePathFlags),
|
}, utils.DatabasePathFlags),
|
||||||
Description: `
|
Description: `
|
||||||
This command dumps out the state for a given block (or latest, if none provided).
|
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) {
|
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 {
|
if ctx.NArg() > 1 {
|
||||||
return nil, nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg())
|
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 {
|
if ctx.NArg() == 1 {
|
||||||
arg := ctx.Args().First()
|
arg := ctx.Args().First()
|
||||||
if hashish(arg) {
|
if hashish(arg) {
|
||||||
@@ -617,11 +645,22 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use latest
|
// Use latest
|
||||||
header = rawdb.ReadHeadHeader(db)
|
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 {
|
if header == nil {
|
||||||
return nil, nil, common.Hash{}, errors.New("no head block found")
|
return nil, nil, common.Hash{}, errors.New("no head block found")
|
||||||
}
|
}
|
||||||
|
|
||||||
startArg := common.FromHex(ctx.String(utils.StartKeyFlag.Name))
|
startArg := common.FromHex(ctx.String(utils.StartKeyFlag.Name))
|
||||||
var start common.Hash
|
var start common.Hash
|
||||||
switch len(startArg) {
|
switch len(startArg) {
|
||||||
@@ -634,6 +673,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
|
|||||||
default:
|
default:
|
||||||
return nil, nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg)
|
return nil, nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg)
|
||||||
}
|
}
|
||||||
|
|
||||||
var conf = &state.DumpConfig{
|
var conf = &state.DumpConfig{
|
||||||
SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name),
|
SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name),
|
||||||
SkipStorage: ctx.Bool(utils.ExcludeStorageFlag.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(),
|
Start: start.Bytes(),
|
||||||
Max: ctx.Uint64(utils.DumpLimitFlag.Name),
|
Max: ctx.Uint64(utils.DumpLimitFlag.Name),
|
||||||
}
|
}
|
||||||
|
conf.StateScheme = scheme
|
||||||
log.Info("State dump configured", "block", header.Number, "hash", header.Hash().Hex(),
|
log.Info("State dump configured", "block", header.Number, "hash", header.Hash().Hex(),
|
||||||
"skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage,
|
"skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage, "start", hexutil.Encode(conf.Start),
|
||||||
"start", hexutil.Encode(conf.Start), "limit", conf.Max)
|
"limit", conf.Max, "state scheme", conf.StateScheme)
|
||||||
return conf, db, header.Root, nil
|
return conf, db, header.Root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -675,6 +716,29 @@ func dump(ctx *cli.Context) error {
|
|||||||
return nil
|
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.
|
// hashish returns true for strings that look like hashes.
|
||||||
func hashish(x string) bool {
|
func hashish(x string) bool {
|
||||||
_, err := strconv.Atoi(x)
|
_, err := strconv.Atoi(x)
|
||||||
|
|||||||
@@ -198,6 +198,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
|||||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||||
cfg.Eth.OverrideVerkle = &v
|
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)
|
backend, _ := utils.RegisterEthService(stack, &cfg.Eth)
|
||||||
|
|
||||||
// Configure log filter RPC API.
|
// Configure log filter RPC API.
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ var (
|
|||||||
utils.OverrideKepler,
|
utils.OverrideKepler,
|
||||||
utils.OverrideCancun,
|
utils.OverrideCancun,
|
||||||
utils.OverrideVerkle,
|
utils.OverrideVerkle,
|
||||||
|
utils.OverrideFeynman,
|
||||||
utils.EnablePersonal,
|
utils.EnablePersonal,
|
||||||
utils.TxPoolLocalsFlag,
|
utils.TxPoolLocalsFlag,
|
||||||
utils.TxPoolNoLocalsFlag,
|
utils.TxPoolNoLocalsFlag,
|
||||||
@@ -239,6 +240,7 @@ func init() {
|
|||||||
removedbCommand,
|
removedbCommand,
|
||||||
dumpCommand,
|
dumpCommand,
|
||||||
dumpGenesisCommand,
|
dumpGenesisCommand,
|
||||||
|
dumpRootHashCommand,
|
||||||
// See accountcmd.go:
|
// See accountcmd.go:
|
||||||
accountCommand,
|
accountCommand,
|
||||||
walletCommand,
|
walletCommand,
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@@ -315,6 +314,11 @@ var (
|
|||||||
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
||||||
Category: flags.EthCategory,
|
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{
|
SyncModeFlag = &flags.TextMarshalerFlag{
|
||||||
Name: "syncmode",
|
Name: "syncmode",
|
||||||
Usage: `Blockchain sync mode ("snap" or "full")`,
|
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) {
|
if ctx.IsSet(StateHistoryFlag.Name) {
|
||||||
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
||||||
}
|
}
|
||||||
scheme, err := compareCLIWithConfig(ctx)
|
scheme, err := ParseCLIAndConfigStateScheme(ctx.String(StateSchemeFlag.Name), cfg.StateScheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("%v", err)
|
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" {
|
if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
|
||||||
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
|
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
|
||||||
}
|
}
|
||||||
provided, err := compareCLIWithConfig(ctx)
|
scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), chainDb)
|
||||||
if err != nil {
|
|
||||||
Fatalf("%v", err)
|
|
||||||
}
|
|
||||||
scheme, err := rawdb.ParseStateScheme(provided, chainDb)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("%v", err)
|
Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
@@ -2425,11 +2425,7 @@ func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, read
|
|||||||
config := &trie.Config{
|
config := &trie.Config{
|
||||||
Preimages: preimage,
|
Preimages: preimage,
|
||||||
}
|
}
|
||||||
provided, err := compareCLIWithConfig(ctx)
|
scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), disk)
|
||||||
if err != nil {
|
|
||||||
Fatalf("%v", err)
|
|
||||||
}
|
|
||||||
scheme, err := rawdb.ParseStateScheme(provided, disk)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("%v", err)
|
Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
@@ -2448,26 +2444,15 @@ func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, read
|
|||||||
return trie.NewDatabase(disk, config)
|
return trie.NewDatabase(disk, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareCLIWithConfig(ctx *cli.Context) (string, error) {
|
// ParseCLIAndConfigStateScheme parses state scheme in CLI and config.
|
||||||
var (
|
func ParseCLIAndConfigStateScheme(cliScheme, cfgScheme string) (string, error) {
|
||||||
cfgScheme string
|
if cliScheme == "" {
|
||||||
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) {
|
|
||||||
if cfgScheme != "" {
|
if cfgScheme != "" {
|
||||||
log.Info("Use config state scheme", "config", cfgScheme)
|
log.Info("Use config state scheme", "config", cfgScheme)
|
||||||
}
|
}
|
||||||
return cfgScheme, nil
|
return cfgScheme, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cliScheme := ctx.String(StateSchemeFlag.Name)
|
|
||||||
if !rawdb.ValidateStateScheme(cliScheme) {
|
if !rawdb.ValidateStateScheme(cliScheme) {
|
||||||
return "", fmt.Errorf("invalid state scheme in CLI: %s", 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)
|
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 ""
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,13 +18,8 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_SplitTagsFlag(t *testing.T) {
|
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
235
consensus/parlia/feynmanfork.go
Normal file
235
consensus/parlia/feynmanfork.go
Normal 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
|
||||||
|
}
|
||||||
166
consensus/parlia/feynmanfork_test.go
Normal file
166
consensus/parlia/feynmanfork_test.go
Normal 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -91,6 +90,11 @@ var (
|
|||||||
common.HexToAddress(systemcontracts.TokenHubContract): true,
|
common.HexToAddress(systemcontracts.TokenHubContract): true,
|
||||||
common.HexToAddress(systemcontracts.RelayerIncentivizeContract): true,
|
common.HexToAddress(systemcontracts.RelayerIncentivizeContract): true,
|
||||||
common.HexToAddress(systemcontracts.CrossChainContract): 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:]
|
signature := header.Extra[len(header.Extra)-extraSeal:]
|
||||||
|
|
||||||
// Recover the public key and the Ethereum address
|
// 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 {
|
if err != nil {
|
||||||
return common.Address{}, err
|
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.
|
// or not), which could be abused to produce different hashes for the same header.
|
||||||
func ParliaRLP(header *types.Header, chainId *big.Int) []byte {
|
func ParliaRLP(header *types.Header, chainId *big.Int) []byte {
|
||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
encodeSigHeader(b, header, chainId)
|
types.EncodeSigHeader(b, header, chainId)
|
||||||
return b.Bytes()
|
return b.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,6 +231,7 @@ type Parlia struct {
|
|||||||
validatorSetABIBeforeLuban abi.ABI
|
validatorSetABIBeforeLuban abi.ABI
|
||||||
validatorSetABI abi.ABI
|
validatorSetABI abi.ABI
|
||||||
slashABI abi.ABI
|
slashABI abi.ABI
|
||||||
|
stakeHubABI abi.ABI
|
||||||
|
|
||||||
// The fields below are for testing only
|
// The fields below are for testing only
|
||||||
fakeDiff bool // Skip difficulty verifications
|
fakeDiff bool // Skip difficulty verifications
|
||||||
@@ -269,6 +274,10 @@ func New(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
stABI, err := abi.JSON(strings.NewReader(stakeABI))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
c := &Parlia{
|
c := &Parlia{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
config: parliaConfig,
|
config: parliaConfig,
|
||||||
@@ -280,6 +289,7 @@ func New(
|
|||||||
validatorSetABIBeforeLuban: vABIBeforeLuban,
|
validatorSetABIBeforeLuban: vABIBeforeLuban,
|
||||||
validatorSetABI: vABI,
|
validatorSetABI: vABI,
|
||||||
slashABI: sABI,
|
slashABI: sABI,
|
||||||
|
stakeHubABI: stABI,
|
||||||
signer: types.LatestSigner(chainConfig),
|
signer: types.LatestSigner(chainConfig),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -908,7 +918,7 @@ func (p *Parlia) assembleVoteAttestation(chain consensus.ChainHeaderReader, head
|
|||||||
// Prepare vote address bitset.
|
// Prepare vote address bitset.
|
||||||
for _, valInfo := range snap.Validators {
|
for _, valInfo := range snap.Validators {
|
||||||
if _, ok := voteAddrSet[valInfo.VoteAddress]; ok {
|
if _, ok := voteAddrSet[valInfo.VoteAddress]; ok {
|
||||||
attestation.VoteAddressSet |= 1 << (valInfo.Index - 1) //Index is offset by 1
|
attestation.VoteAddressSet |= 1 << (valInfo.Index - 1) // Index is offset by 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
validatorsBitSet := bitset.From([]uint64{uint64(attestation.VoteAddressSet)})
|
validatorsBitSet := bitset.From([]uint64{uint64(attestation.VoteAddressSet)})
|
||||||
@@ -1117,6 +1127,22 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
|
|||||||
|
|
||||||
cx := chainContext{Chain: chain, parlia: p}
|
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
|
// No block rewards in PoA, so the state remains as is and uncles are dropped
|
||||||
if header.Number.Cmp(common.Big1) == 0 {
|
if header.Number.Cmp(common.Big1) == 0 {
|
||||||
err := p.initContract(state, header, cx, txs, receipts, systemTxs, usedGas, false)
|
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
|
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 {
|
if len(*systemTxs) > 0 {
|
||||||
return errors.New("the length of systemTxs do not match")
|
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 {
|
if receipts == nil {
|
||||||
receipts = make([]*types.Receipt, 0)
|
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 {
|
if header.Number.Cmp(common.Big1) == 0 {
|
||||||
err := p.initContract(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true)
|
err := p.initContract(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true)
|
||||||
if err != nil {
|
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
|
// should not happen. Once happen, stop the node is better than broadcast the block
|
||||||
if header.GasLimit < header.GasUsed {
|
if header.GasLimit < header.GasUsed {
|
||||||
return nil, nil, errors.New("gas consumption of system txs exceed the gas limit")
|
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 {
|
select {
|
||||||
case results <- block.WithSeal(header):
|
case results <- block.WithSeal(header):
|
||||||
default:
|
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
|
// 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) {
|
func (p *Parlia) SealHash(header *types.Header) (hash common.Hash) {
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := sha3.NewLegacyKeccak256()
|
||||||
encodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
|
types.EncodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
|
||||||
hasher.Sum(hash[:0])
|
hasher.Sum(hash[:0])
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
@@ -1554,19 +1618,18 @@ func (p *Parlia) getCurrentValidators(blockHash common.Hash, blockNum *big.Int)
|
|||||||
|
|
||||||
var valSet []common.Address
|
var valSet []common.Address
|
||||||
var voteAddrSet []types.BLSPublicKey
|
var voteAddrSet []types.BLSPublicKey
|
||||||
|
|
||||||
if err := p.validatorSetABI.UnpackIntoInterface(&[]interface{}{&valSet, &voteAddrSet}, method, result); err != nil {
|
if err := p.validatorSetABI.UnpackIntoInterface(&[]interface{}{&valSet, &voteAddrSet}, method, result); err != nil {
|
||||||
return nil, nil, err
|
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++ {
|
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,
|
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 {
|
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool) error {
|
||||||
coinbase := header.Coinbase
|
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) &&
|
doDistributeSysReward := !p.chainConfig.IsKepler(header.Number, header.Time) &&
|
||||||
state.GetBalance(common.HexToAddress(systemcontracts.SystemRewardContract)).Cmp(maxSystemBalance) < 0
|
state.GetBalance(common.HexToAddress(systemcontracts.SystemRewardContract)).Cmp(maxSystemBalance) < 0
|
||||||
if doDistributeSysReward {
|
if doDistributeSysReward {
|
||||||
var rewards = new(big.Int)
|
rewards := new(big.Int)
|
||||||
rewards = rewards.Rsh(balance, systemRewardPercent)
|
rewards = rewards.Rsh(balance, systemRewardPercent)
|
||||||
if rewards.Cmp(common.Big0) > 0 {
|
if rewards.Cmp(common.Big0) > 0 {
|
||||||
err := p.distributeToSystem(rewards, state, header, chain, txs, receipts, receivedTxs, usedGas, mining)
|
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)
|
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,
|
func (p *Parlia) distributeToValidator(amount *big.Int, validator common.Address,
|
||||||
state *state.StateDB, header *types.Header, chain core.ChainContext,
|
state *state.StateDB, header *types.Header, chain core.ChainContext,
|
||||||
txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool) error {
|
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.BlockNumber = header.Number
|
||||||
receipt.TransactionIndex = uint(state.TxIndex())
|
receipt.TransactionIndex = uint(state.TxIndex())
|
||||||
*receipts = append(*receipts, receipt)
|
*receipts = append(*receipts, receipt)
|
||||||
state.SetNonce(msg.From(), nonce+1)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1802,62 +1864,6 @@ func (p *Parlia) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================== utility function ==========================
|
// =========================== 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 {
|
func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Address) uint64 {
|
||||||
if snap.inturn(val) {
|
if snap.inturn(val) {
|
||||||
return 0
|
return 0
|
||||||
@@ -1975,6 +1981,8 @@ func applyMessage(
|
|||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEVM(context, vm.TxContext{Origin: msg.From(), GasPrice: big.NewInt(0)}, state, chainConfig, vm.Config{})
|
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)
|
// 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(
|
ret, returnGas, err := vmenv.Call(
|
||||||
vm.AccountRef(msg.From()),
|
vm.AccountRef(msg.From()),
|
||||||
*msg.To(),
|
*msg.To(),
|
||||||
|
|||||||
@@ -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 {
|
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
|
||||||
misc.ApplyDAOHardFork(statedb)
|
misc.ApplyDAOHardFork(statedb)
|
||||||
}
|
}
|
||||||
systemcontracts.UpgradeBuildInSystemContract(config, b.header.Number, parent.Time(), b.header.Time, 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
|
// Execute any user modifications to the block
|
||||||
if gen != nil {
|
if gen != nil {
|
||||||
gen(i, b)
|
gen(i, b)
|
||||||
|
|||||||
@@ -276,10 +276,12 @@ func (e *GenesisMismatchError) Error() string {
|
|||||||
// ChainOverrides contains the changes to chain config
|
// ChainOverrides contains the changes to chain config
|
||||||
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
|
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
|
||||||
type ChainOverrides struct {
|
type ChainOverrides struct {
|
||||||
OverrideShanghai *uint64
|
OverrideShanghai *uint64
|
||||||
OverrideKepler *uint64
|
OverrideKepler *uint64
|
||||||
OverrideCancun *uint64
|
OverrideCancun *uint64
|
||||||
OverrideVerkle *uint64
|
OverrideVerkle *uint64
|
||||||
|
OverrideFeynman *uint64
|
||||||
|
OverrideFeynmanFix *uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupGenesisBlock writes or updates the genesis block in db.
|
// 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 {
|
if overrides != nil && overrides.OverrideVerkle != nil {
|
||||||
config.VerkleTime = overrides.OverrideVerkle
|
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.
|
// Just commit the new block if there is no stored genesis block.
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ func ParseStateScheme(provided string, disk ethdb.Database) (string, error) {
|
|||||||
if stored == "" {
|
if stored == "" {
|
||||||
// use default scheme for empty database, flip it when
|
// use default scheme for empty database, flip it when
|
||||||
// path mode is chosen as default
|
// 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
|
return HashScheme, nil
|
||||||
}
|
}
|
||||||
log.Info("State scheme set to already existing disk db", "scheme", stored)
|
log.Info("State scheme set to already existing disk db", "scheme", stored)
|
||||||
|
|||||||
@@ -129,6 +129,8 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
|
|||||||
switch freezerName {
|
switch freezerName {
|
||||||
case chainFreezerName:
|
case chainFreezerName:
|
||||||
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
|
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
|
||||||
|
case stateFreezerName:
|
||||||
|
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown freezer, supported ones: %v", freezers)
|
return fmt.Errorf("unknown freezer, supported ones: %v", freezers)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,19 +188,27 @@ func (batch *freezerTableBatch) maybeCommit() error {
|
|||||||
|
|
||||||
// commit writes the batched items to the backing freezerTable.
|
// commit writes the batched items to the backing freezerTable.
|
||||||
func (batch *freezerTableBatch) commit() error {
|
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)
|
_, err := batch.t.head.Write(batch.dataBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := batch.t.head.Sync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
dataSize := int64(len(batch.dataBuffer))
|
dataSize := int64(len(batch.dataBuffer))
|
||||||
batch.dataBuffer = batch.dataBuffer[:0]
|
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)
|
_, err = batch.t.index.Write(batch.indexBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := batch.t.index.Sync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
indexSize := int64(len(batch.indexBuffer))
|
indexSize := int64(len(batch.indexBuffer))
|
||||||
batch.indexBuffer = batch.indexBuffer[:0]
|
batch.indexBuffer = batch.indexBuffer[:0]
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,9 @@ func (t *freezerTable) repair() error {
|
|||||||
if t.readonly {
|
if t.readonly {
|
||||||
return fmt.Errorf("index file(path: %s, name: %s) size is not a multiple of %d", t.path, t.name, indexEntrySize)
|
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
|
// Retrieve the file sizes and prepare for truncation
|
||||||
if stat, err = t.index.Stat(); err != nil {
|
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
|
// 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
|
// 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.
|
// by storing all zero-size items, it is highly unlikely to occur in practice.
|
||||||
if lastIndex.offset == 0 && offsetsSize%indexEntrySize > 1 {
|
if lastIndex.offset == 0 && offsetsSize/indexEntrySize > 1 {
|
||||||
log.Error("Corrupted index file detected", "lastOffset", lastIndex.offset, "items", offsetsSize%indexEntrySize-1)
|
log.Error("Corrupted index file detected", "lastOffset", lastIndex.offset, "indexes", offsetsSize/indexEntrySize)
|
||||||
}
|
}
|
||||||
if t.readonly {
|
if t.readonly {
|
||||||
t.head, err = t.openFile(lastIndex.filenum, openFreezerFileForReadOnly)
|
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 {
|
if err := truncateFreezerFile(t.index, int64(length+1)*indexEntrySize); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := t.index.Sync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Calculate the new expected size of the data file and truncate it
|
// Calculate the new expected size of the data file and truncate it
|
||||||
var expected indexEntry
|
var expected indexEntry
|
||||||
if length == 0 {
|
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
|
// Release any files _after the current head -- both the previous head
|
||||||
// and any files which may have been opened for reading
|
// and any files which may have been opened for reading
|
||||||
t.releaseFilesAfter(expected.filenum, true)
|
t.releaseFilesAfter(expected.filenum, true)
|
||||||
|
|
||||||
// Set back the historic head
|
// Set back the historic head
|
||||||
t.head = newHead
|
t.head = newHead
|
||||||
t.headId = expected.filenum
|
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 {
|
if err := truncateFreezerFile(t.head, int64(expected.offset)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := t.head.Sync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// All data files truncated, set internal counters and return
|
// All data files truncated, set internal counters and return
|
||||||
t.headBytes = int64(expected.offset)
|
t.headBytes = int64(expected.offset)
|
||||||
t.items.Store(items)
|
t.items.Store(items)
|
||||||
@@ -597,10 +606,12 @@ func (t *freezerTable) Close() error {
|
|||||||
// error on Windows.
|
// error on Windows.
|
||||||
doClose(t.index, true, true)
|
doClose(t.index, true, true)
|
||||||
doClose(t.meta, true, true)
|
doClose(t.meta, true, true)
|
||||||
|
|
||||||
// The preopened non-head data-files are all opened in readonly.
|
// 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
|
// 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.
|
// part of t.files, it will be closed in the loop below.
|
||||||
doClose(t.head, true, false) // sync but do not close
|
doClose(t.head, true, false) // sync but do not close
|
||||||
|
|
||||||
for _, f := range t.files {
|
for _, f := range t.files {
|
||||||
doClose(f, false, true) // close but do not sync
|
doClose(f, false, true) // close but do not sync
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,11 +73,7 @@ func copyFrom(srcPath, destPath string, offset uint64, before func(f *os.File) e
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
f = nil
|
f = nil
|
||||||
|
return os.Rename(fname, destPath)
|
||||||
if err := os.Rename(fname, destPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// openFreezerFileForAppend opens a freezer table file and seeks to the end
|
// openFreezerFileForAppend opens a freezer table file and seeks to the end
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"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/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@@ -37,6 +38,7 @@ type DumpConfig struct {
|
|||||||
OnlyWithAddresses bool
|
OnlyWithAddresses bool
|
||||||
Start []byte
|
Start []byte
|
||||||
Max uint64
|
Max uint64
|
||||||
|
StateScheme string
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpCollector interface which the state trie calls during iteration
|
// DumpCollector interface which the state trie calls during iteration
|
||||||
@@ -57,7 +59,6 @@ type DumpAccount struct {
|
|||||||
Storage map[common.Hash]string `json:"storage,omitempty"`
|
Storage map[common.Hash]string `json:"storage,omitempty"`
|
||||||
Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode
|
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
|
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.
|
// 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 {
|
if !conf.SkipStorage {
|
||||||
account.Storage = make(map[common.Hash]string)
|
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 {
|
if err != nil {
|
||||||
log.Error("Failed to load storage trie", "err", err)
|
log.Error("Failed to load storage trie", "err", err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -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 {
|
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
||||||
misc.ApplyDAOHardFork(statedb)
|
misc.ApplyDAOHardFork(statedb)
|
||||||
}
|
}
|
||||||
// Handle upgrade build-in system contract code
|
|
||||||
lastBlock := p.bc.GetBlockByHash(block.ParentHash())
|
lastBlock := p.bc.GetBlockByHash(block.ParentHash())
|
||||||
if lastBlock == nil {
|
if lastBlock == nil {
|
||||||
return statedb, nil, nil, 0, fmt.Errorf("could not get parent block")
|
return statedb, nil, nil, 0, fmt.Errorf("could not get parent block")
|
||||||
}
|
}
|
||||||
systemcontracts.UpgradeBuildInSystemContract(p.config, blockNumber, lastBlock.Time(), block.Time(), statedb)
|
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 (
|
var (
|
||||||
context = NewEVMBlockContext(header, p.bc, nil)
|
context = NewEVMBlockContext(header, p.bc, nil)
|
||||||
|
|||||||
@@ -13,4 +13,10 @@ const (
|
|||||||
TokenManagerContract = "0x0000000000000000000000000000000000001008"
|
TokenManagerContract = "0x0000000000000000000000000000000000001008"
|
||||||
CrossChainContract = "0x0000000000000000000000000000000000002000"
|
CrossChainContract = "0x0000000000000000000000000000000000002000"
|
||||||
StakingContract = "0x0000000000000000000000000000000000002001"
|
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
@@ -57,10 +57,6 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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
|
// ErrTxPoolOverflow is returned if the transaction pool is full and can't accept
|
||||||
// another remote transaction.
|
// another remote transaction.
|
||||||
ErrTxPoolOverflow = errors.New("txpool is full")
|
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 {
|
if pool.all.Get(hash) != nil {
|
||||||
log.Trace("Discarding already known transaction", "hash", hash)
|
log.Trace("Discarding already known transaction", "hash", hash)
|
||||||
knownTxMeter.Mark(1)
|
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
|
// 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.
|
// 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 {
|
for i, tx := range txs {
|
||||||
// If the transaction is known, pre-set the error slot
|
// If the transaction is known, pre-set the error slot
|
||||||
if pool.all.Get(tx.Hash()) != nil {
|
if pool.all.Get(tx.Hash()) != nil {
|
||||||
errs[i] = ErrAlreadyKnown
|
errs[i] = txpool.ErrAlreadyKnown
|
||||||
knownTxMeter.Mark(1)
|
knownTxMeter.Mark(1)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"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 {
|
if err := s.Decode(&ed); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.BlockHash, d.Number, d.Codes, d.Destructs, d.Accounts, d.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
|
||||||
ed.BlockHash, ed.Number, ed.Codes, ed.Destructs, ed.Accounts, ed.Storages
|
|
||||||
|
|
||||||
d.Receipts = make([]*Receipt, len(ed.Receipts))
|
d.Receipts = make([]*Receipt, len(ed.Receipts))
|
||||||
for i, storageReceipt := range 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.Keys[i], storage.Keys[j] = storage.Keys[j], storage.Keys[i]
|
||||||
storage.Vals[i], storage.Vals[j] = storage.Vals[j], storage.Vals[i]
|
storage.Vals[i], storage.Vals[j] = storage.Vals[j], storage.Vals[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *DiffStorage) Less(i, j int) bool {
|
func (storage *DiffStorage) Less(i, j int) bool {
|
||||||
return string(storage.Keys[i][:]) < string(storage.Keys[j][:])
|
return string(storage.Keys[i][:]) < string(storage.Keys[j][:])
|
||||||
}
|
}
|
||||||
@@ -622,3 +624,64 @@ type DiffAccountsInBlock struct {
|
|||||||
BlockHash common.Hash
|
BlockHash common.Hash
|
||||||
Transactions []DiffAccountsInTx
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,23 +17,28 @@
|
|||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/crypto/blake2b"
|
"github.com/ethereum/go-ethereum/crypto/blake2b"
|
||||||
"github.com/ethereum/go-ethereum/crypto/bls12381"
|
"github.com/ethereum/go-ethereum/crypto/bls12381"
|
||||||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"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/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/crypto/ripemd160"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrecompiledContract is the basic interface for native Go contracts. The implementation
|
// 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{101}): &iavlMerkleProofValidatePlato{},
|
||||||
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
|
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
|
||||||
common.BytesToAddress([]byte{103}): &cometBFTLightBlockValidate{},
|
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
|
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
|
||||||
@@ -245,6 +273,7 @@ var (
|
|||||||
PrecompiledAddressesIstanbul []common.Address
|
PrecompiledAddressesIstanbul []common.Address
|
||||||
PrecompiledAddressesByzantium []common.Address
|
PrecompiledAddressesByzantium []common.Address
|
||||||
PrecompiledAddressesHomestead []common.Address
|
PrecompiledAddressesHomestead []common.Address
|
||||||
|
PrecompiledAddressesFeynman []common.Address
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -281,6 +310,9 @@ func init() {
|
|||||||
for k := range PrecompiledContractsCancun {
|
for k := range PrecompiledContractsCancun {
|
||||||
PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k)
|
PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k)
|
||||||
}
|
}
|
||||||
|
for k := range PrecompiledContractsFeynman {
|
||||||
|
PrecompiledAddressesFeynman = append(PrecompiledAddressesFeynman, k)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActivePrecompiles returns the precompiles enabled with the current configuration.
|
// ActivePrecompiles returns the precompiles enabled with the current configuration.
|
||||||
@@ -288,6 +320,8 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
|
|||||||
switch {
|
switch {
|
||||||
case rules.IsCancun:
|
case rules.IsCancun:
|
||||||
return PrecompiledAddressesCancun
|
return PrecompiledAddressesCancun
|
||||||
|
case rules.IsFeynman:
|
||||||
|
return PrecompiledAddressesFeynman
|
||||||
case rules.IsHertz:
|
case rules.IsHertz:
|
||||||
return PrecompiledAddressesHertz
|
return PrecompiledAddressesHertz
|
||||||
case rules.IsPlato:
|
case rules.IsPlato:
|
||||||
@@ -561,7 +595,7 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
|
|||||||
// Modulo 0 is undefined, return zero
|
// Modulo 0 is undefined, return zero
|
||||||
return common.LeftPadBytes([]byte{}, int(modLen)), nil
|
return common.LeftPadBytes([]byte{}, int(modLen)), nil
|
||||||
case base.BitLen() == 1: // a bit length of 1 means it's 1 (or -1).
|
case base.BitLen() == 1: // a bit length of 1 means it's 1 (or -1).
|
||||||
//If base == 1, then we can just return base % mod (if mod >= 1, which it is)
|
// If base == 1, then we can just return base % mod (if mod >= 1, which it is)
|
||||||
v = base.Mod(base, mod).Bytes()
|
v = base.Mod(base, mod).Bytes()
|
||||||
default:
|
default:
|
||||||
v = base.Exp(base, exp, mod).Bytes()
|
v = base.Exp(base, exp, mod).Bytes()
|
||||||
@@ -1355,3 +1389,95 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
|
|||||||
|
|
||||||
return h
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ import (
|
|||||||
|
|
||||||
"github.com/tendermint/iavl"
|
"github.com/tendermint/iavl"
|
||||||
"github.com/tendermint/tendermint/crypto/merkle"
|
"github.com/tendermint/tendermint/crypto/merkle"
|
||||||
|
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
|
||||||
|
//nolint:staticcheck
|
||||||
v1 "github.com/ethereum/go-ethereum/core/vm/lightclient/v1"
|
v1 "github.com/ethereum/go-ethereum/core/vm/lightclient/v1"
|
||||||
v2 "github.com/ethereum/go-ethereum/core/vm/lightclient/v2"
|
v2 "github.com/ethereum/go-ethereum/core/vm/lightclient/v2"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
@@ -104,7 +106,7 @@ func (c *tmHeaderValidate) Run(input []byte) (result []byte, err error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// iavlMerkleProofValidate implemented as a native contract.
|
// iavlMerkleProofValidate implemented as a native contract.
|
||||||
type iavlMerkleProofValidate struct {
|
type iavlMerkleProofValidate struct {
|
||||||
@@ -397,3 +399,40 @@ type cometBFTLightBlockValidateHertz struct {
|
|||||||
func (c *cometBFTLightBlockValidateHertz) Run(input []byte) (result []byte, err error) {
|
func (c *cometBFTLightBlockValidateHertz) Run(input []byte) (result []byte, err error) {
|
||||||
return c.run(input, true)
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -373,3 +373,42 @@ func TestCometBFTLightBlockValidateHertz(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectOutputStr, hex.EncodeToString(res))
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
|
|||||||
common.BytesToAddress([]byte{0x0f, 0x11}): &bls12381MapG1{},
|
common.BytesToAddress([]byte{0x0f, 0x11}): &bls12381MapG1{},
|
||||||
common.BytesToAddress([]byte{0x0f, 0x12}): &bls12381MapG2{},
|
common.BytesToAddress([]byte{0x0f, 0x12}): &bls12381MapG2{},
|
||||||
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
|
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
|
||||||
|
common.BytesToAddress([]byte{104}): &verifyDoubleSignEvidence{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// EIP-152 test vectors
|
// EIP-152 test vectors
|
||||||
@@ -405,3 +406,24 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
|
|||||||
}
|
}
|
||||||
benchmarkPrecompiled("0f", testcase, 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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
|
|||||||
switch {
|
switch {
|
||||||
case evm.chainRules.IsCancun:
|
case evm.chainRules.IsCancun:
|
||||||
precompiles = PrecompiledContractsCancun
|
precompiles = PrecompiledContractsCancun
|
||||||
|
case evm.chainRules.IsFeynman:
|
||||||
|
precompiles = PrecompiledContractsFeynman
|
||||||
case evm.chainRules.IsHertz:
|
case evm.chainRules.IsHertz:
|
||||||
precompiles = PrecompiledContractsHertz
|
precompiles = PrecompiledContractsHertz
|
||||||
case evm.chainRules.IsPlato:
|
case evm.chainRules.IsPlato:
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
|
|||||||
if stateDb == nil {
|
if stateDb == nil {
|
||||||
return state.Dump{}, errors.New("pending state is not available")
|
return state.Dump{}, errors.New("pending state is not available")
|
||||||
}
|
}
|
||||||
|
opts.StateScheme = stateDb.Database().TrieDB().Scheme()
|
||||||
return stateDb.RawDump(opts), nil
|
return stateDb.RawDump(opts), nil
|
||||||
}
|
}
|
||||||
var header *types.Header
|
var header *types.Header
|
||||||
@@ -83,6 +84,7 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return state.Dump{}, err
|
return state.Dump{}, err
|
||||||
}
|
}
|
||||||
|
opts.StateScheme = stateDb.Database().TrieDB().Scheme()
|
||||||
return stateDb.RawDump(opts), nil
|
return stateDb.RawDump(opts), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +190,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
|
|||||||
OnlyWithAddresses: !incompletes,
|
OnlyWithAddresses: !incompletes,
|
||||||
Start: start,
|
Start: start,
|
||||||
Max: uint64(maxResults),
|
Max: uint64(maxResults),
|
||||||
|
StateScheme: stateDb.Database().TrieDB().Scheme(),
|
||||||
}
|
}
|
||||||
if maxResults > AccountRangeMaxResults || maxResults <= 0 {
|
if maxResults > AccountRangeMaxResults || maxResults <= 0 {
|
||||||
opts.Max = AccountRangeMaxResults
|
opts.Max = AccountRangeMaxResults
|
||||||
|
|||||||
@@ -189,6 +189,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
chainConfig.VerkleTime = config.OverrideVerkle
|
chainConfig.VerkleTime = config.OverrideVerkle
|
||||||
overrides.OverrideVerkle = 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{
|
eth := &Ethereum{
|
||||||
config: config,
|
config: config,
|
||||||
|
|||||||
@@ -197,6 +197,12 @@ type Config struct {
|
|||||||
|
|
||||||
// OverrideVerkle (TODO: remove after the fork)
|
// OverrideVerkle (TODO: remove after the fork)
|
||||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
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.
|
// CreateConsensusEngine creates a consensus engine for the given chain config.
|
||||||
|
|||||||
@@ -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 'other reject' is >25% of the deliveries in any batch, sleep a bit.
|
||||||
if otherreject > 128/4 {
|
if otherreject > 128/4 {
|
||||||
time.Sleep(200 * time.Millisecond)
|
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 {
|
select {
|
||||||
|
|||||||
@@ -227,8 +227,8 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL
|
|||||||
if p < 0 || p > 100 {
|
if p < 0 || p > 100 {
|
||||||
return common.Big0, nil, nil, nil, fmt.Errorf("%w: %f", errInvalidPercentile, p)
|
return common.Big0, nil, nil, nil, fmt.Errorf("%w: %f", errInvalidPercentile, p)
|
||||||
}
|
}
|
||||||
if i > 0 && p < rewardPercentiles[i-1] {
|
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)
|
return common.Big0, nil, nil, nil, fmt.Errorf("%w: #%d:%f >= #%d:%f", errInvalidPercentile, i-1, rewardPercentiles[i-1], i, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -381,8 +381,6 @@ func (h *handler) protoTracker() {
|
|||||||
<-h.handlerDoneCh
|
<-h.handlerDoneCh
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case <-h.stopCh:
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
@@ -239,12 +240,37 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, err
|
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 {
|
if txIndex == 0 && len(block.Transactions()) == 0 {
|
||||||
return nil, vm.BlockContext{}, statedb, release, nil
|
return nil, vm.BlockContext{}, statedb, release, nil
|
||||||
}
|
}
|
||||||
// Recompute transactions up to the target index.
|
// 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() {
|
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
|
// Assemble the transaction call message and return if the requested offset
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
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
|
// Not yet the searched for transaction, execute on top of the current state
|
||||||
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
|
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)
|
statedb.SetTxContext(tx.Hash(), idx)
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
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)
|
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||||
|
|||||||
@@ -132,8 +132,6 @@ func (cs *chainSyncer) loop() {
|
|||||||
<-cs.doneCh
|
<-cs.doneCh
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case <-cs.handler.stopCh:
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
@@ -187,6 +188,7 @@ type txTraceResult struct {
|
|||||||
// being traced.
|
// being traced.
|
||||||
type blockTraceTask struct {
|
type blockTraceTask struct {
|
||||||
statedb *state.StateDB // Intermediate state prepped for tracing
|
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
|
block *types.Block // Block to trace the transactions from
|
||||||
release StateReleaseFunc // The function to release the held resource for this task
|
release StateReleaseFunc // The function to release the held resource for this task
|
||||||
results []*txTraceResult // Trace results produced by the task
|
results []*txTraceResult // Trace results produced by the task
|
||||||
@@ -203,8 +205,9 @@ type blockTraceResult struct {
|
|||||||
// txTraceTask represents a single transaction trace task when an entire block
|
// txTraceTask represents a single transaction trace task when an entire block
|
||||||
// is being traced.
|
// is being traced.
|
||||||
type txTraceTask struct {
|
type txTraceTask struct {
|
||||||
statedb *state.StateDB // Intermediate state prepped for tracing
|
statedb *state.StateDB // Intermediate state prepped for tracing
|
||||||
index int // Transaction offset in the block
|
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
|
// TraceChain returns the structured logs created during the execution of EVM
|
||||||
@@ -267,11 +270,30 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
|||||||
// Fetch and execute the block trace taskCh
|
// Fetch and execute the block trace taskCh
|
||||||
for task := range taskCh {
|
for task := range taskCh {
|
||||||
var (
|
var (
|
||||||
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
|
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
|
||||||
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
|
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
|
||||||
|
beforeSystemTx = true
|
||||||
)
|
)
|
||||||
// Trace all the transactions contained within
|
// Trace all the transactions contained within
|
||||||
for i, tx := range task.block.Transactions() {
|
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())
|
msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: task.block.Hash(),
|
BlockHash: task.block.Hash(),
|
||||||
@@ -279,7 +301,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
|||||||
TxIndex: i,
|
TxIndex: i,
|
||||||
TxHash: tx.Hash(),
|
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 {
|
if err != nil {
|
||||||
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
|
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
|
||||||
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
|
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.
|
// may fail if we release too early.
|
||||||
tracker.callReleases()
|
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)
|
// Send the block over to the concurrent tracers (if not in the fast-forward phase)
|
||||||
txs := next.Transactions()
|
txs := next.Transactions()
|
||||||
select {
|
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:
|
case <-closed:
|
||||||
tracker.releaseState(number, release)
|
tracker.releaseState(number, release)
|
||||||
return
|
return
|
||||||
@@ -522,12 +549,18 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
|||||||
}
|
}
|
||||||
defer release()
|
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 (
|
var (
|
||||||
roots []common.Hash
|
roots []common.Hash
|
||||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||||
chainConfig = api.backend.ChainConfig()
|
chainConfig = api.backend.ChainConfig()
|
||||||
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
|
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
|
||||||
|
beforeSystemTx = true
|
||||||
)
|
)
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
if err := ctx.Err(); err != nil {
|
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.SetBalance(consensus.SystemAddress, big.NewInt(0))
|
||||||
statedb.AddBalance(vmctx.Coinbase, balance)
|
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()
|
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
|
// JS tracers have high overhead. In this case run a parallel
|
||||||
// process that generates states in one thread and traces txes
|
// process that generates states in one thread and traces txes
|
||||||
// in separate worker threads.
|
// in separate worker threads.
|
||||||
@@ -610,16 +653,36 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||||||
return api.traceBlockParallel(ctx, block, statedb, config)
|
return api.traceBlockParallel(ctx, block, statedb, config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Native tracers have low overhead
|
// Native tracers have low overhead
|
||||||
var (
|
var (
|
||||||
txs = block.Transactions()
|
txs = block.Transactions()
|
||||||
blockHash = block.Hash()
|
blockHash = block.Hash()
|
||||||
is158 = api.backend.ChainConfig().IsEIP158(block.Number())
|
is158 = api.backend.ChainConfig().IsEIP158(block.Number())
|
||||||
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||||
results = make([]*txTraceResult, len(txs))
|
results = make([]*txTraceResult, len(txs))
|
||||||
|
beforeSystemTx = true
|
||||||
)
|
)
|
||||||
for i, tx := range txs {
|
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
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
@@ -628,7 +691,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||||||
TxIndex: i,
|
TxIndex: i,
|
||||||
TxHash: tx.Hash(),
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -672,7 +735,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
|
|||||||
TxIndex: task.index,
|
TxIndex: task.index,
|
||||||
TxHash: txs[task.index].Hash(),
|
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 {
|
if err != nil {
|
||||||
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
|
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
|
||||||
continue
|
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
|
// Feed the transactions into the tracers and return
|
||||||
var failed error
|
var (
|
||||||
|
failed error
|
||||||
|
beforeSystemTx = true
|
||||||
|
)
|
||||||
txloop:
|
txloop:
|
||||||
for i, tx := range txs {
|
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
|
// Send the trace task over for execution
|
||||||
task := &txTraceTask{statedb: statedb.Copy(), index: i}
|
task := &txTraceTask{statedb: statedb.Copy(), index: i, isSystemTx: !beforeSystemTx}
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
failed = ctx.Err()
|
failed = ctx.Err()
|
||||||
@@ -697,15 +786,6 @@ txloop:
|
|||||||
|
|
||||||
// Generate the next state snapshot fast without tracing
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
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)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
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 {
|
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()
|
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
|
// Retrieve the tracing configurations, or use default values
|
||||||
var (
|
var (
|
||||||
logConfig logger.Config
|
logConfig logger.Config
|
||||||
@@ -767,11 +852,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
|||||||
|
|
||||||
// Execute transaction, either tracing all or just the requested one
|
// Execute transaction, either tracing all or just the requested one
|
||||||
var (
|
var (
|
||||||
dumps []string
|
dumps []string
|
||||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||||
chainConfig = api.backend.ChainConfig()
|
chainConfig = api.backend.ChainConfig()
|
||||||
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
canon = true
|
canon = true
|
||||||
|
beforeSystemTx = true
|
||||||
)
|
)
|
||||||
// Check if there are any overrides: the caller may wish to enable a future
|
// 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
|
// 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
|
// Note: This copies the config, to not screw up the main config
|
||||||
chainConfig, canon = overrideConfig(chainConfig, config.Overrides)
|
chainConfig, canon = overrideConfig(chainConfig, config.Overrides)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tx := range block.Transactions() {
|
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
|
// Prepare the transaction for un-traced execution
|
||||||
var (
|
var (
|
||||||
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
|
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
|
// Execute the transaction and flush any traces to disk
|
||||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
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)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||||
if writer != nil {
|
if writer != nil {
|
||||||
@@ -887,13 +983,20 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
|||||||
}
|
}
|
||||||
defer release()
|
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{
|
txctx := &Context{
|
||||||
BlockHash: blockHash,
|
BlockHash: blockHash,
|
||||||
BlockNumber: block.Number(),
|
BlockNumber: block.Number(),
|
||||||
TxIndex: int(index),
|
TxIndex: int(index),
|
||||||
TxHash: hash,
|
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
|
// 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()
|
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)
|
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
// Apply the customization rules if required.
|
// Apply the customization rules if required.
|
||||||
if config != nil {
|
if config != nil {
|
||||||
@@ -952,13 +1066,13 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||||||
if config != nil {
|
if config != nil {
|
||||||
traceConfig = &config.TraceConfig
|
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
|
// traceTx configures a new tracer according to the provided configuration, and
|
||||||
// executes the given message in the provided environment. The return value will
|
// executes the given message in the provided environment. The return value will
|
||||||
// be tracer dependent.
|
// 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 (
|
var (
|
||||||
tracer Tracer
|
tracer Tracer
|
||||||
err error
|
err error
|
||||||
@@ -997,13 +1111,7 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte
|
|||||||
|
|
||||||
var intrinsicGas uint64 = 0
|
var intrinsicGas uint64 = 0
|
||||||
// Run the transaction with tracing enabled.
|
// Run the transaction with tracing enabled.
|
||||||
if posa, ok := api.backend.Engine().(consensus.PoSA); ok && message.From == vmctx.Coinbase &&
|
if isSystemTx {
|
||||||
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)
|
|
||||||
}
|
|
||||||
intrinsicGas, _ = core.IntrinsicGas(message.Data, message.AccessList, false, true, true, false)
|
intrinsicGas, _ = core.IntrinsicGas(message.Data, message.AccessList, false, true, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ func TestTraceCall(t *testing.T) {
|
|||||||
},
|
},
|
||||||
config: nil,
|
config: nil,
|
||||||
expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
|
expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
|
||||||
//expect: nil,
|
// expect: nil,
|
||||||
},
|
},
|
||||||
// Standard JSON trace upon the latest block
|
// Standard JSON trace upon the latest block
|
||||||
{
|
{
|
||||||
@@ -547,7 +547,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||||||
Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number()
|
Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number()
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
//Tracer: &tracer,
|
// Tracer: &tracer,
|
||||||
StateOverrides: ðapi.StateOverride{
|
StateOverrides: ðapi.StateOverride{
|
||||||
randomAccounts[2].addr: ethapi.OverrideAccount{
|
randomAccounts[2].addr: ethapi.OverrideAccount{
|
||||||
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")),
|
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")),
|
||||||
@@ -563,7 +563,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||||||
From: &accounts[0].addr,
|
From: &accounts[0].addr,
|
||||||
// BLOCKNUMBER PUSH1 MSTORE
|
// BLOCKNUMBER PUSH1 MSTORE
|
||||||
Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")),
|
Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")),
|
||||||
//&hexutil.Bytes{0x43}, // blocknumber
|
// &hexutil.Bytes{0x43}, // blocknumber
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||||
@@ -639,7 +639,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
//want: `{"gas":46900,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000539"}`,
|
// want: `{"gas":46900,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000539"}`,
|
||||||
want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`,
|
want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`,
|
||||||
},
|
},
|
||||||
{ // No state override
|
{ // No state override
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -234,7 +234,7 @@ require (
|
|||||||
github.com/prysmaticlabs/prysm v0.0.0-20220124113610-e26cde5e091b // indirect
|
github.com/prysmaticlabs/prysm v0.0.0-20220124113610-e26cde5e091b // indirect
|
||||||
github.com/quic-go/qpack v0.4.0 // 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/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/quic-go/webtransport-go v0.6.0 // indirect
|
||||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // 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/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/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/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
8
go.sum
@@ -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/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 h1:DvjGOts2FBfbxB48384CYD1LbcrfjThFz8kowY/7KxU=
|
||||||
github.com/bnb-chain/ics23 v0.1.0/go.mod h1:cU6lTGolbbLFsGCgceNB2AzplH1xecLp6+KXvxM32nI=
|
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.16 h1:rOO6WG61JDAuRCCL8TKnGhorJftQDVygq0mqR7A0ck4=
|
||||||
github.com/bnb-chain/tendermint v0.31.15/go.mod h1:cmt8HHmQUSVaWQ/hoTefRxsh5X3ERaM1zCUIR0DPbFU=
|
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/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/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=
|
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/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 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/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.4 h1:PelfiuG7wXEffUT2yceiqz5V6Pc0TA5ruOd1LcmFc1s=
|
||||||
github.com/quic-go/quic-go v0.39.3/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
|
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 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
|
||||||
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
|
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=
|
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc/go.mod h1:S8xSOnV3CgpNrWd0GQ/OoQfMtlg2uPRSuTzcSGrzwK8=
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const backupTimeFormat = "2006-01-02_15"
|
||||||
|
|
||||||
type TimeTicker struct {
|
type TimeTicker struct {
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
C <-chan time.Time
|
C <-chan time.Time
|
||||||
@@ -69,19 +71,24 @@ type AsyncFileWriter struct {
|
|||||||
buf chan []byte
|
buf chan []byte
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
timeTicker *TimeTicker
|
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)
|
absFilePath, err := filepath.Abs(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("get file path of logger error. filePath=%s, err=%s", filePath, err))
|
panic(fmt.Sprintf("get file path of logger error. filePath=%s, err=%s", filePath, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &AsyncFileWriter{
|
return &AsyncFileWriter{
|
||||||
filePath: absFilePath,
|
filePath: absFilePath,
|
||||||
buf: make(chan []byte, maxBytesSize),
|
buf: make(chan []byte, maxBytesSize),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
timeTicker: NewTimeTicker(rotateHours),
|
rotateHours: rotateHours,
|
||||||
|
maxBackups: maxBackups,
|
||||||
|
timeTicker: NewTimeTicker(rotateHours),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +185,9 @@ func (w *AsyncFileWriter) rotateFile() {
|
|||||||
if err := w.initLogFile(); err != nil {
|
if err := w.initLogFile(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "init log file error. err=%s", err)
|
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:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,5 +232,29 @@ func (w *AsyncFileWriter) flushAndClose() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *AsyncFileWriter) timeFilePath(filePath string) string {
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWriterHourly(t *testing.T) {
|
func TestWriterHourly(t *testing.T) {
|
||||||
w := NewAsyncFileWriter("./hello.log", 100, 1)
|
w := NewAsyncFileWriter("./hello.log", 100, 1, 1)
|
||||||
w.Start()
|
w.Start()
|
||||||
w.Write([]byte("hello\n"))
|
w.Write([]byte("hello\n"))
|
||||||
w.Write([]byte("world\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))
|
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))
|
||||||
|
}
|
||||||
|
|||||||
@@ -75,14 +75,14 @@ func FileHandler(path string, fmtr Format) (Handler, error) {
|
|||||||
// RotatingFileHandler returns a handler which writes log records to file chunks
|
// 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
|
// 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.
|
// 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) {
|
if _, err := os.Stat(path.Dir(filePath)); os.IsNotExist(err) {
|
||||||
err := os.MkdirAll(path.Dir(filePath), 0755)
|
err := os.MkdirAll(path.Dir(filePath), 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not create directory %s, %v", path.Dir(filePath), err)
|
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()
|
fileWriter.Start()
|
||||||
return StreamHandler(fileWriter, formatter), nil
|
return StreamHandler(fileWriter, formatter), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,8 +290,8 @@ func (c Ctx) toArray() []interface{} {
|
|||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileLvlHandler(logPath string, maxBytesSize uint, level string, rotateHours uint) Handler {
|
func NewFileLvlHandler(logPath string, maxBytesSize uint, maxBackups uint, level string, rotateHours uint) Handler {
|
||||||
rfh, err := RotatingFileHandler(logPath, maxBytesSize, LogfmtFormat(), rotateHours)
|
rfh, err := RotatingFileHandler(logPath, maxBytesSize, maxBackups, LogfmtFormat(), rotateHours)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -724,7 +724,7 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
|
|||||||
|
|
||||||
stopPrefetchCh := make(chan struct{})
|
stopPrefetchCh := make(chan struct{})
|
||||||
defer close(stopPrefetchCh)
|
defer close(stopPrefetchCh)
|
||||||
//prefetch txs from all pending txs
|
// prefetch txs from all pending txs
|
||||||
txsPrefetch := txs.Copy()
|
txsPrefetch := txs.Copy()
|
||||||
tx := txsPrefetch.PeekWithUnwrap()
|
tx := txsPrefetch.PeekWithUnwrap()
|
||||||
if tx != nil {
|
if tx != nil {
|
||||||
@@ -909,8 +909,10 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle upgrade build-in system contract code
|
if !w.chainConfig.IsFeynman(header.Number, header.Time) {
|
||||||
systemcontracts.UpgradeBuildInSystemContract(w.chainConfig, header.Number, parent.Time, header.Time, env.state)
|
// Handle upgrade build-in system contract code
|
||||||
|
systemcontracts.UpgradeBuildInSystemContract(w.chainConfig, header.Number, parent.Time, header.Time, env.state)
|
||||||
|
}
|
||||||
|
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -513,6 +513,7 @@ type LogConfig struct {
|
|||||||
MaxBytesSize *uint `toml:",omitempty"`
|
MaxBytesSize *uint `toml:",omitempty"`
|
||||||
Level *string `toml:",omitempty"`
|
Level *string `toml:",omitempty"`
|
||||||
RotateHours *uint `toml:",omitempty"`
|
RotateHours *uint `toml:",omitempty"`
|
||||||
|
MaxBackups *uint `toml:",omitempty"`
|
||||||
|
|
||||||
// TermTimeFormat is the time format used for console logging.
|
// TermTimeFormat is the time format used for console logging.
|
||||||
TermTimeFormat *string `toml:",omitempty"`
|
TermTimeFormat *string `toml:",omitempty"`
|
||||||
|
|||||||
@@ -118,7 +118,12 @@ func New(conf *Config) (*Node, error) {
|
|||||||
rotateHours = *conf.LogConfig.RotateHours
|
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 {
|
if conf.Logger == nil {
|
||||||
|
|||||||
@@ -65,9 +65,6 @@ const (
|
|||||||
|
|
||||||
// Maximum amount of time allowed for writing a complete message.
|
// Maximum amount of time allowed for writing a complete message.
|
||||||
frameWriteTimeout = 20 * time.Second
|
frameWriteTimeout = 20 * time.Second
|
||||||
|
|
||||||
// Maximum time to wait before stop the p2p server
|
|
||||||
stopTimeout = 5 * time.Second
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -457,7 +454,7 @@ func (srv *Server) Stop() {
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-stopChan:
|
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")
|
srv.log.Warn("stop p2p server timeout, forcing stop")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,8 +223,8 @@ func TestServerStopTimeout(t *testing.T) {
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-stopChan:
|
case <-stopChan:
|
||||||
case <-time.After(10 * time.Second):
|
case <-time.After(defaultDialTimeout + 1*time.Second):
|
||||||
t.Error("server should be shutdown in 10 seconds")
|
t.Error("server should be shutdown in defaultDialTimeout + 1 seconds")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,9 @@ var (
|
|||||||
ShanghaiTime: newUint64(1705996800),
|
ShanghaiTime: newUint64(1705996800),
|
||||||
KeplerTime: newUint64(1705996800),
|
KeplerTime: newUint64(1705996800),
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
FeynmanTime: nil,
|
||||||
|
|
||||||
Parlia: &ParliaConfig{
|
Parlia: &ParliaConfig{
|
||||||
Period: 3,
|
Period: 3,
|
||||||
Epoch: 200,
|
Epoch: 200,
|
||||||
@@ -183,6 +186,10 @@ var (
|
|||||||
// UnixTime: 1702972800 is December 19, 2023 8:00:00 AM UTC
|
// UnixTime: 1702972800 is December 19, 2023 8:00:00 AM UTC
|
||||||
ShanghaiTime: newUint64(1702972800),
|
ShanghaiTime: newUint64(1702972800),
|
||||||
KeplerTime: newUint64(1702972800),
|
KeplerTime: newUint64(1702972800),
|
||||||
|
FeynmanTime: newUint64(1710136800),
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
FeynmanFixTime: nil,
|
||||||
|
|
||||||
Parlia: &ParliaConfig{
|
Parlia: &ParliaConfig{
|
||||||
Period: 3,
|
Period: 3,
|
||||||
@@ -219,10 +226,12 @@ var (
|
|||||||
HertzfixBlock: big.NewInt(8),
|
HertzfixBlock: big.NewInt(8),
|
||||||
ShanghaiTime: newUint64(0),
|
ShanghaiTime: newUint64(0),
|
||||||
KeplerTime: newUint64(0),
|
KeplerTime: newUint64(0),
|
||||||
|
FeynmanTime: _rialto_upgrade_height_,
|
||||||
|
FeynmanFixTime: _rialto_upgrade_height_,
|
||||||
|
|
||||||
Parlia: &ParliaConfig{
|
Parlia: &ParliaConfig{
|
||||||
Period: 3,
|
Period: _rialto_parlia_period_,
|
||||||
Epoch: 200,
|
Epoch: _rialto_parlia_epoch_,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,11 +463,13 @@ type ChainConfig struct {
|
|||||||
|
|
||||||
// Fork scheduling was switched from blocks to timestamps here
|
// Fork scheduling was switched from blocks to timestamps here
|
||||||
|
|
||||||
ShanghaiTime *uint64 `json:"shanghaiTime,omitempty" ` // Shanghai switch time (nil = no fork, 0 = already on shanghai)
|
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)
|
KeplerTime *uint64 `json:"keplerTime,omitempty"` // Kepler switch time (nil = no fork, 0 = already activated)
|
||||||
CancunTime *uint64 `json:"cancunTime,omitempty" ` // Cancun switch time (nil = no fork, 0 = already on cancun)
|
FeynmanTime *uint64 `json:"feynmanTime,omitempty"` // Feynman switch time (nil = no fork, 0 = already activated)
|
||||||
PragueTime *uint64 `json:"pragueTime,omitempty" ` // Prague switch time (nil = no fork, 0 = already on prague)
|
FeynmanFixTime *uint64 `json:"feynmanFixTime,omitempty"` // Feynman switch time (nil = no fork, 0 = already activated)
|
||||||
VerkleTime *uint64 `json:"verkleTime,omitempty" ` // Verkle switch time (nil = no fork, 0 = already on verkle)
|
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)
|
||||||
|
|
||||||
// TerminalTotalDifficulty is the amount of total difficulty reached by
|
// TerminalTotalDifficulty is the amount of total difficulty reached by
|
||||||
// the network that triggers the consensus upgrade.
|
// the network that triggers the consensus upgrade.
|
||||||
@@ -548,7 +559,17 @@ func (c *ChainConfig) String() string {
|
|||||||
KeplerTime = big.NewInt(0).SetUint64(*c.KeplerTime)
|
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.ChainID,
|
||||||
c.HomesteadBlock,
|
c.HomesteadBlock,
|
||||||
c.DAOForkBlock,
|
c.DAOForkBlock,
|
||||||
@@ -582,6 +603,8 @@ func (c *ChainConfig) String() string {
|
|||||||
c.HertzfixBlock,
|
c.HertzfixBlock,
|
||||||
ShanghaiTime,
|
ShanghaiTime,
|
||||||
KeplerTime,
|
KeplerTime,
|
||||||
|
FeynmanTime,
|
||||||
|
FeynmanFixTime,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -816,6 +839,34 @@ func (c *ChainConfig) IsOnKepler(currentBlockNumber *big.Int, lastBlockTime uint
|
|||||||
return !c.IsKepler(lastBlockNumber, lastBlockTime) && c.IsKepler(currentBlockNumber, currentBlockTime)
|
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.
|
// IsCancun returns whether num is either equal to the Cancun fork time or greater.
|
||||||
func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool {
|
func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool {
|
||||||
return c.IsLondon(num) && isTimestampForked(c.CancunTime, time)
|
return c.IsLondon(num) && isTimestampForked(c.CancunTime, time)
|
||||||
@@ -881,6 +932,8 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
|
|||||||
{name: "hertzBlock", block: c.HertzBlock},
|
{name: "hertzBlock", block: c.HertzBlock},
|
||||||
{name: "hertzfixBlock", block: c.HertzfixBlock},
|
{name: "hertzfixBlock", block: c.HertzfixBlock},
|
||||||
{name: "keplerTime", timestamp: c.KeplerTime},
|
{name: "keplerTime", timestamp: c.KeplerTime},
|
||||||
|
{name: "feynmanTime", timestamp: c.FeynmanTime},
|
||||||
|
{name: "feynmanFixTime", timestamp: c.FeynmanFixTime},
|
||||||
{name: "cancunTime", timestamp: c.CancunTime, optional: true},
|
{name: "cancunTime", timestamp: c.CancunTime, optional: true},
|
||||||
{name: "pragueTime", timestamp: c.PragueTime, optional: true},
|
{name: "pragueTime", timestamp: c.PragueTime, optional: true},
|
||||||
{name: "verkleTime", timestamp: c.VerkleTime, 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) {
|
if isForkTimestampIncompatible(c.KeplerTime, newcfg.KeplerTime, headTimestamp) {
|
||||||
return newTimestampCompatError("Kepler fork timestamp", c.KeplerTime, newcfg.KeplerTime)
|
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) {
|
if isForkTimestampIncompatible(c.CancunTime, newcfg.CancunTime, headTimestamp) {
|
||||||
return newTimestampCompatError("Cancun fork timestamp", c.CancunTime, newcfg.CancunTime)
|
return newTimestampCompatError("Cancun fork timestamp", c.CancunTime, newcfg.CancunTime)
|
||||||
}
|
}
|
||||||
@@ -1181,7 +1240,7 @@ type Rules struct {
|
|||||||
IsPlato bool
|
IsPlato bool
|
||||||
IsHertz bool
|
IsHertz bool
|
||||||
IsHertzfix bool
|
IsHertzfix bool
|
||||||
IsShanghai, IsKepler, IsCancun, IsPrague bool
|
IsShanghai, IsKepler, IsFeynman, IsCancun, IsPrague bool
|
||||||
IsVerkle bool
|
IsVerkle bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1213,6 +1272,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
|
|||||||
IsHertzfix: c.IsHertzfix(num),
|
IsHertzfix: c.IsHertzfix(num),
|
||||||
IsShanghai: c.IsShanghai(num, timestamp),
|
IsShanghai: c.IsShanghai(num, timestamp),
|
||||||
IsKepler: c.IsKepler(num, timestamp),
|
IsKepler: c.IsKepler(num, timestamp),
|
||||||
|
IsFeynman: c.IsFeynman(num, timestamp),
|
||||||
IsCancun: c.IsCancun(num, timestamp),
|
IsCancun: c.IsCancun(num, timestamp),
|
||||||
IsPrague: c.IsPrague(num, timestamp),
|
IsPrague: c.IsPrague(num, timestamp),
|
||||||
IsVerkle: c.IsVerkle(num, timestamp),
|
IsVerkle: c.IsVerkle(num, timestamp),
|
||||||
|
|||||||
@@ -24,19 +24,19 @@ const (
|
|||||||
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
||||||
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
||||||
|
|
||||||
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
|
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
|
||||||
ForkIDSize uint64 = 4 // The length of fork id
|
ForkIDSize uint64 = 4 // The length of fork id
|
||||||
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
|
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
|
||||||
SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
|
SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
|
||||||
CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero.
|
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.
|
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.
|
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.
|
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.
|
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.
|
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
|
||||||
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
|
LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
|
||||||
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
CallStipend uint64 = 2300 // Free gas given at beginning of call.
|
||||||
|
|
||||||
Keccak256Gas uint64 = 30 // Once per KECCAK256 operation.
|
Keccak256Gas uint64 = 30 // Once per KECCAK256 operation.
|
||||||
Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data.
|
Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data.
|
||||||
@@ -135,15 +135,16 @@ const (
|
|||||||
IAVLMerkleProofValidateGas uint64 = 3000 // Gas for validate merkle proof
|
IAVLMerkleProofValidateGas uint64 = 3000 // Gas for validate merkle proof
|
||||||
CometBFTLightBlockValidateGas uint64 = 3000 // Gas for validate cometBFT light block
|
CometBFTLightBlockValidateGas uint64 = 3000 // Gas for validate cometBFT light block
|
||||||
|
|
||||||
EcrecoverGas uint64 = 3000 // Elliptic curve sender recovery gas price
|
EcrecoverGas uint64 = 3000 // Elliptic curve sender recovery gas price
|
||||||
Sha256BaseGas uint64 = 60 // Base price for a SHA256 operation
|
Sha256BaseGas uint64 = 60 // Base price for a SHA256 operation
|
||||||
Sha256PerWordGas uint64 = 12 // Per-word price for a SHA256 operation
|
Sha256PerWordGas uint64 = 12 // Per-word price for a SHA256 operation
|
||||||
Ripemd160BaseGas uint64 = 600 // Base price for a RIPEMD160 operation
|
Ripemd160BaseGas uint64 = 600 // Base price for a RIPEMD160 operation
|
||||||
Ripemd160PerWordGas uint64 = 120 // Per-word price for a RIPEMD160 operation
|
Ripemd160PerWordGas uint64 = 120 // Per-word price for a RIPEMD160 operation
|
||||||
IdentityBaseGas uint64 = 15 // Base price for a data copy operation
|
IdentityBaseGas uint64 = 15 // Base price for a data copy operation
|
||||||
IdentityPerWordGas uint64 = 3 // Per-work price for a data copy operation
|
IdentityPerWordGas uint64 = 3 // Per-work price for a data copy operation
|
||||||
BlsSignatureVerifyBaseGas uint64 = 1000 // base price for a BLS signature verify operation
|
BlsSignatureVerifyBaseGas uint64 = 1000 // base price for a BLS signature verify operation
|
||||||
BlsSignatureVerifyPerKeyGas uint64 = 3500 // Per-key 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
|
Bn256AddGasByzantium uint64 = 500 // Byzantium gas needed for an elliptic curve addition
|
||||||
Bn256AddGasIstanbul uint64 = 150 // Gas needed for an elliptic curve addition
|
Bn256AddGasIstanbul uint64 = 150 // Gas needed for an elliptic curve addition
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
VersionMajor = 1 // Major version component of the current release
|
VersionMajor = 1 // Major version component of the current release
|
||||||
VersionMinor = 3 // Minor 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
|
VersionMeta = "" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ func parliaHeaderHashAndRlp(header *types.Header, chainId *big.Int) (hash, rlp [
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
rlp = parlia.ParliaRLP(header, chainId)
|
rlp = parlia.ParliaRLP(header, chainId)
|
||||||
hash = parlia.SealHash(header, chainId).Bytes()
|
hash = types.SealHash(header, chainId).Bytes()
|
||||||
return hash, rlp, err
|
return hash, rlp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ func (db *Database) SetBufferSize(size int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Head return the top non-fork difflayer/disklayer root hash for rewinding.
|
// 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.
|
// others.
|
||||||
func (db *Database) Head() common.Hash {
|
func (db *Database) Head() common.Hash {
|
||||||
pdb, ok := db.backend.(*pathdb.Database)
|
pdb, ok := db.backend.(*pathdb.Database)
|
||||||
@@ -364,3 +364,15 @@ func (db *Database) Head() common.Hash {
|
|||||||
}
|
}
|
||||||
return pdb.Head()
|
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()
|
||||||
|
}
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ func (nc *nodecache) node(owner common.Hash, path []byte, hash common.Hash) (*tr
|
|||||||
}
|
}
|
||||||
if n.Hash != hash {
|
if n.Hash != hash {
|
||||||
dirtyFalseMeter.Mark(1)
|
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 nil, newUnexpectedNodeError("dirty", hash, n.Hash, owner, path, n.Blob)
|
||||||
}
|
}
|
||||||
return n, nil
|
return n, nil
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -441,3 +443,24 @@ func (db *Database) Head() common.Hash {
|
|||||||
defer db.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
return db.tree.front()
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user