mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
Merge remote-tracking branch 'upstream/develop' into block-stm
This commit is contained in:
commit
a093c4e7df
54 changed files with 1398 additions and 505 deletions
234
.github/workflows/packager.yml
vendored
234
.github/workflows/packager.yml
vendored
|
|
@ -47,7 +47,7 @@ jobs:
|
|||
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: amd64
|
||||
|
||||
|
||||
- name: Running package build
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
|
|
@ -61,6 +61,116 @@ jobs:
|
|||
- name: Copying systemd file
|
||||
run: cp -rp packaging/templates/systemd/bor.service packaging/deb/bor/lib/systemd/system/bor.service
|
||||
|
||||
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} bootnode for ${{ env.ARCH }}
|
||||
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: any
|
||||
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/testnet-v4/sentry/sentry/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: any
|
||||
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: any
|
||||
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: any
|
||||
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: any
|
||||
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: any
|
||||
- name: Copying profile control file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/control.profile.amd64 packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/control
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Running package build for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
|
||||
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} bootnode for ${{ env.ARCH }}
|
||||
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/mainnet-v1/sentry/sentry/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying profile control file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/control.profile.amd64 packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/control
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Running package build for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
|
||||
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} node for ${{ env.ARCH }}
|
||||
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
|
|
@ -366,7 +476,7 @@ jobs:
|
|||
ARCH: amd64
|
||||
NODE: archive
|
||||
NETWORK: mainnet
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: amd64
|
||||
|
|
@ -416,6 +526,116 @@ jobs:
|
|||
- name: Updating the control file to use with the arm64 profile
|
||||
run: cp -rp packaging/templates/package_scripts/control.profile.arm64 packaging/deb/bor/DEBIAN/control
|
||||
|
||||
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} bootnode for ${{ env.ARCH }}
|
||||
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/testnet-v4/sentry/sentry/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Copying profile control file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/control.profile.amd64 packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/control
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Running package build for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
|
||||
- name: Prepping ${{ env.NETWORK }} ${{ env.NODE }} bootnode for ${{ env.ARCH }}
|
||||
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Putting toml for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/mainnet-v1/sentry/sentry/bor/config.toml packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/var/lib/bor/
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying the preinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/preinst packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/preinst
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying the postinst for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/postinst.profile packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postinst
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying the prerm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/prerm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/prerm
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying the postrm for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/postrm packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/postrm
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying profile control file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/package_scripts/control.profile.amd64 packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/DEBIAN/control
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Running package build for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
|
||||
- name: Setting up bor for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/deb/bor packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
|
|
@ -519,7 +739,7 @@ jobs:
|
|||
ARCH: arm64
|
||||
NODE: sentry
|
||||
NETWORK: mainnet
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: arm64
|
||||
|
|
@ -629,13 +849,13 @@ jobs:
|
|||
ARCH: arm64
|
||||
NODE: validator
|
||||
NETWORK: mainnet
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: arm64
|
||||
NODE: validator
|
||||
NETWORK: mainnet
|
||||
|
||||
|
||||
- name: Updating the control file to use with the arm64 profile
|
||||
run: cp -rp packaging/templates/package_scripts/control.profile.arm64 packaging/deb/bor/DEBIAN/control
|
||||
|
||||
|
|
@ -675,7 +895,7 @@ jobs:
|
|||
ARCH: arm64
|
||||
NODE: archive
|
||||
NETWORK: mumbai
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: arm64
|
||||
|
|
@ -718,7 +938,7 @@ jobs:
|
|||
ARCH: arm64
|
||||
NODE: archive
|
||||
NETWORK: mainnet
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
- name: Building bor ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }} profile
|
||||
run: dpkg-deb --build --root-owner-group packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}
|
||||
env:
|
||||
ARCH: arm64
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -17,7 +17,7 @@ GIT_COMMIT ?= $(shell git rev-list -1 HEAD)
|
|||
|
||||
PACKAGE = github.com/ethereum/go-ethereum
|
||||
GO_FLAGS += -buildvcs=false
|
||||
GO_LDFLAGS += -ldflags "-X ${PACKAGE}/params.GitCommit=${GIT_COMMIT} "
|
||||
GO_LDFLAGS += -ldflags "-X ${PACKAGE}/params.GitCommit=${GIT_COMMIT}"
|
||||
|
||||
TESTALL = $$(go list ./... | grep -v go-ethereum/cmd/)
|
||||
TESTE2E = ./tests/...
|
||||
|
|
|
|||
|
|
@ -637,8 +637,8 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
|||
// about the transaction and calling mechanisms.
|
||||
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
||||
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
|
||||
return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb()
|
||||
// nolint : contextcheck
|
||||
return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb(context.Background())
|
||||
}
|
||||
|
||||
// SendTransaction updates the pending block to include the given transaction.
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
|
||||
|
||||
// (ret []byte, usedGas uint64, failed bool, err error)
|
||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool, nil)
|
||||
if err != nil {
|
||||
statedb.RevertToSnapshot(snapshot)
|
||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
|
||||
|
|
|
|||
|
|
@ -75,13 +75,34 @@ func rankMapDifficulties(values map[common.Address]uint64) []difficultiesKV {
|
|||
}
|
||||
|
||||
// GetSnapshotProposerSequence retrieves the in-turn signers of all sprints in a span
|
||||
func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigners, error) {
|
||||
snapNumber := *number - 1
|
||||
func (api *API) GetSnapshotProposerSequence(blockNrOrHash *rpc.BlockNumberOrHash) (BlockSigners, error) {
|
||||
var header *types.Header
|
||||
//nolint:nestif
|
||||
if blockNrOrHash == nil {
|
||||
header = api.chain.CurrentHeader()
|
||||
} else {
|
||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||
if blockNr == rpc.LatestBlockNumber {
|
||||
header = api.chain.CurrentHeader()
|
||||
} else {
|
||||
header = api.chain.GetHeaderByNumber(uint64(blockNr))
|
||||
}
|
||||
} else {
|
||||
if blockHash, ok := blockNrOrHash.Hash(); ok {
|
||||
header = api.chain.GetHeaderByHash(blockHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if header == nil {
|
||||
return BlockSigners{}, errUnknownBlock
|
||||
}
|
||||
|
||||
snapNumber := rpc.BlockNumber(header.Number.Int64() - 1)
|
||||
snap, err := api.GetSnapshot(&snapNumber)
|
||||
|
||||
var difficulties = make(map[common.Address]uint64)
|
||||
|
||||
snap, err := api.GetSnapshot(&snapNumber)
|
||||
|
||||
if err != nil {
|
||||
return BlockSigners{}, err
|
||||
}
|
||||
|
|
@ -101,7 +122,7 @@ func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigne
|
|||
|
||||
rankedDifficulties := rankMapDifficulties(difficulties)
|
||||
|
||||
author, err := api.GetAuthor(number)
|
||||
author, err := api.GetAuthor(blockNrOrHash)
|
||||
if err != nil {
|
||||
return BlockSigners{}, err
|
||||
}
|
||||
|
|
@ -117,9 +138,31 @@ func (api *API) GetSnapshotProposerSequence(number *rpc.BlockNumber) (BlockSigne
|
|||
}
|
||||
|
||||
// GetSnapshotProposer retrieves the in-turn signer at a given block.
|
||||
func (api *API) GetSnapshotProposer(number *rpc.BlockNumber) (common.Address, error) {
|
||||
*number -= 1
|
||||
snap, err := api.GetSnapshot(number)
|
||||
func (api *API) GetSnapshotProposer(blockNrOrHash *rpc.BlockNumberOrHash) (common.Address, error) {
|
||||
var header *types.Header
|
||||
//nolint:nestif
|
||||
if blockNrOrHash == nil {
|
||||
header = api.chain.CurrentHeader()
|
||||
} else {
|
||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||
if blockNr == rpc.LatestBlockNumber {
|
||||
header = api.chain.CurrentHeader()
|
||||
} else {
|
||||
header = api.chain.GetHeaderByNumber(uint64(blockNr))
|
||||
}
|
||||
} else {
|
||||
if blockHash, ok := blockNrOrHash.Hash(); ok {
|
||||
header = api.chain.GetHeaderByHash(blockHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if header == nil {
|
||||
return common.Address{}, errUnknownBlock
|
||||
}
|
||||
|
||||
snapNumber := rpc.BlockNumber(header.Number.Int64() - 1)
|
||||
snap, err := api.GetSnapshot(&snapNumber)
|
||||
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
|
|
@ -129,14 +172,26 @@ func (api *API) GetSnapshotProposer(number *rpc.BlockNumber) (common.Address, er
|
|||
}
|
||||
|
||||
// GetAuthor retrieves the author a block.
|
||||
func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) {
|
||||
func (api *API) GetAuthor(blockNrOrHash *rpc.BlockNumberOrHash) (*common.Address, error) {
|
||||
// Retrieve the requested block number (or current if none requested)
|
||||
var header *types.Header
|
||||
if number == nil || *number == rpc.LatestBlockNumber {
|
||||
|
||||
//nolint:nestif
|
||||
if blockNrOrHash == nil {
|
||||
header = api.chain.CurrentHeader()
|
||||
} else {
|
||||
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
|
||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||
header = api.chain.GetHeaderByNumber(uint64(blockNr))
|
||||
if blockNr == rpc.LatestBlockNumber {
|
||||
header = api.chain.CurrentHeader()
|
||||
}
|
||||
} else {
|
||||
if blockHash, ok := blockNrOrHash.Hash(); ok {
|
||||
header = api.chain.GetHeaderByHash(blockHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we have an actually valid block and return its snapshot
|
||||
if header == nil {
|
||||
return nil, errUnknownBlock
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ func ApplyMessage(
|
|||
msg.Data(),
|
||||
msg.Gas(),
|
||||
msg.Value(),
|
||||
nil,
|
||||
)
|
||||
// Update the state with pending changes
|
||||
if err != nil {
|
||||
|
|
@ -104,6 +105,7 @@ func ApplyBorMessage(vmenv vm.EVM, msg Callmsg) (*core.ExecutionResult, error) {
|
|||
msg.Data(),
|
||||
msg.Gas(),
|
||||
msg.Value(),
|
||||
nil,
|
||||
)
|
||||
// Update the state with pending changes
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
|
|||
b.SetCoinbase(common.Address{})
|
||||
}
|
||||
b.statedb.Prepare(tx.Hash(), len(b.txs))
|
||||
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
|
||||
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ func (task *ExecutionTask) Execute(mvh *blockstm.MVHashMap, incarnation int) (er
|
|||
|
||||
// Apply the transaction to the current state (included in the env).
|
||||
if *task.shouldDelayFeeCal {
|
||||
task.result, err = ApplyMessageNoFeeBurnOrTip(evm, task.msg, new(GasPool).AddGas(task.gasLimit))
|
||||
task.result, err = ApplyMessageNoFeeBurnOrTip(evm, task.msg, new(GasPool).AddGas(task.gasLimit), nil)
|
||||
|
||||
if task.result == nil || err != nil {
|
||||
return blockstm.ErrExecAbortError{Dependency: task.statedb.DepTxIndex(), OriginError: err}
|
||||
|
|
@ -137,7 +137,7 @@ func (task *ExecutionTask) Execute(mvh *blockstm.MVHashMap, incarnation int) (er
|
|||
task.shouldRerunWithoutFeeDelay = true
|
||||
}
|
||||
} else {
|
||||
task.result, err = ApplyMessage(evm, task.msg, new(GasPool).AddGas(task.gasLimit))
|
||||
task.result, err = ApplyMessage(evm, task.msg, new(GasPool).AddGas(task.gasLimit), nil)
|
||||
}
|
||||
|
||||
if task.statedb.HadInvalidRead() || err != nil {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
|
|
@ -89,6 +90,6 @@ func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool
|
|||
// Update the evm with the new transaction context.
|
||||
evm.Reset(NewEVMTxContext(msg), statedb)
|
||||
// Add addresses to access list if applicable
|
||||
_, err := ApplyMessage(evm, msg, gaspool)
|
||||
_, err := ApplyMessage(evm, msg, gaspool, context.Background())
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
statedb.Prepare(tx.Hash(), i)
|
||||
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
|
||||
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, nil)
|
||||
if err != nil {
|
||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
|
|
@ -101,7 +101,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
return receipts, allLogs, *usedGas, nil
|
||||
}
|
||||
|
||||
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
||||
// nolint : unparam
|
||||
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, interruptCtx context.Context) (*types.Receipt, error) {
|
||||
// Create a new context to be used in the EVM environment.
|
||||
txContext := NewEVMTxContext(msg)
|
||||
evm.Reset(txContext, statedb)
|
||||
|
|
@ -120,7 +121,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
|
|||
// resume recording read and write
|
||||
statedb.SetMVHashmap(backupMVHashMap)
|
||||
|
||||
result, err = ApplyMessageNoFeeBurnOrTip(evm, msg, gp)
|
||||
result, err = ApplyMessageNoFeeBurnOrTip(evm, msg, gp, interruptCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -151,6 +152,10 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
|
|||
output2.Add(output2, result.FeeTipped),
|
||||
)
|
||||
|
||||
if result.Err == vm.ErrInterrupt {
|
||||
return nil, result.Err
|
||||
}
|
||||
|
||||
// Update the state with pending changes.
|
||||
var root []byte
|
||||
if config.IsByzantium(blockNumber) {
|
||||
|
|
@ -189,7 +194,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
|
|||
// and uses the input parameters for its environment. It returns the receipt
|
||||
// for the transaction, gas used and an error if the transaction failed,
|
||||
// indicating the block was invalid.
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, interruptCtx context.Context) (*types.Receipt, error) {
|
||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -197,5 +202,6 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
|||
// Create a new context to be used in the EVM environment
|
||||
blockContext := NewEVMBlockContext(header, bc, author)
|
||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
|
||||
return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
|
||||
|
||||
return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv, interruptCtx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
|
|
@ -188,15 +189,15 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
|||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||
// indicates a core error meaning that the message would always fail for that particular
|
||||
// state and would never be accepted within a block.
|
||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
|
||||
return NewStateTransition(evm, msg, gp).TransitionDb()
|
||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool, interruptCtx context.Context) (*ExecutionResult, error) {
|
||||
return NewStateTransition(evm, msg, gp).TransitionDb(interruptCtx)
|
||||
}
|
||||
|
||||
func ApplyMessageNoFeeBurnOrTip(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
|
||||
func ApplyMessageNoFeeBurnOrTip(evm *vm.EVM, msg Message, gp *GasPool, interruptCtx context.Context) (*ExecutionResult, error) {
|
||||
st := NewStateTransition(evm, msg, gp)
|
||||
st.noFeeBurnAndTip = true
|
||||
|
||||
return st.TransitionDb()
|
||||
return st.TransitionDb(interruptCtx)
|
||||
}
|
||||
|
||||
// to returns the recipient of the message.
|
||||
|
|
@ -290,7 +291,7 @@ func (st *StateTransition) preCheck() error {
|
|||
//
|
||||
// However if any consensus issue encountered, return the error directly with
|
||||
// nil evm execution result.
|
||||
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||
func (st *StateTransition) TransitionDb(interruptCtx context.Context) (*ExecutionResult, error) {
|
||||
input1 := st.state.GetBalance(st.msg.From())
|
||||
|
||||
var input2 *big.Int
|
||||
|
|
@ -348,7 +349,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
|||
} else {
|
||||
// Increment the nonce for the next transaction
|
||||
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
|
||||
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
|
||||
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value, interruptCtx)
|
||||
}
|
||||
|
||||
if !london {
|
||||
|
|
|
|||
|
|
@ -1815,7 +1815,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
|
||||
chainConfig.LondonBlock = big.NewInt(0)
|
||||
|
||||
_, back, closeFn := miner.NewTestWorker(t, chainConfig, engine, db, 0, 0, 0)
|
||||
_, back, closeFn := miner.NewTestWorker(t, chainConfig, engine, db, 0, 0, 0, 0)
|
||||
defer closeFn()
|
||||
|
||||
genesis := back.BlockChain().Genesis()
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -165,7 +166,7 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
|
|||
// parameters. It also handles any necessary value transfer required and takes
|
||||
// the necessary steps to create accounts and reverses the state in case of an
|
||||
// execution error or failed value transfer.
|
||||
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, interruptCtx context.Context) (ret []byte, leftOverGas uint64, err error) {
|
||||
// Fail if we're trying to execute above the call depth limit
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
|
|
@ -225,7 +226,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
// The depth-check is already done, and precompiles handled above
|
||||
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
|
||||
ret, err = evm.interpreter.Run(contract, input, false)
|
||||
ret, err = evm.interpreter.PreRun(contract, input, false, interruptCtx)
|
||||
gas = contract.Gas
|
||||
}
|
||||
}
|
||||
|
|
@ -282,7 +283,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
// The contract is a scoped environment for this execution context only.
|
||||
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
ret, err = evm.interpreter.Run(contract, input, false)
|
||||
ret, err = evm.interpreter.PreRun(contract, input, false, nil)
|
||||
gas = contract.Gas
|
||||
}
|
||||
if err != nil {
|
||||
|
|
@ -322,7 +323,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
// Initialise a new contract and make initialise the delegate values
|
||||
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
ret, err = evm.interpreter.Run(contract, input, false)
|
||||
ret, err = evm.interpreter.PreRun(contract, input, false, nil)
|
||||
gas = contract.Gas
|
||||
}
|
||||
if err != nil {
|
||||
|
|
@ -378,7 +379,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
// when we're in Homestead this also counts for code storage gas errors.
|
||||
ret, err = evm.interpreter.Run(contract, input, true)
|
||||
ret, err = evm.interpreter.PreRun(contract, input, true, nil)
|
||||
gas = contract.Gas
|
||||
}
|
||||
if err != nil {
|
||||
|
|
@ -450,7 +451,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
|
||||
start := time.Now()
|
||||
|
||||
ret, err := evm.interpreter.Run(contract, nil, false)
|
||||
ret, err := evm.interpreter.PreRun(contract, nil, false, nil)
|
||||
|
||||
// Check whether the max code size has been exceeded, assign err if the case.
|
||||
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ func TestEIP2200(t *testing.T) {
|
|||
}
|
||||
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}})
|
||||
|
||||
_, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(big.Int))
|
||||
_, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(big.Int), nil)
|
||||
if err != tt.failure {
|
||||
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,16 +392,21 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
|||
// opExtCodeHash returns the code hash of a specified account.
|
||||
// There are several cases when the function is called, while we can relay everything
|
||||
// to `state.GetCodeHash` function to ensure the correctness.
|
||||
// (1) Caller tries to get the code hash of a normal contract account, state
|
||||
//
|
||||
// (1) Caller tries to get the code hash of a normal contract account, state
|
||||
//
|
||||
// should return the relative code hash and set it as the result.
|
||||
//
|
||||
// (2) Caller tries to get the code hash of a non-existent account, state should
|
||||
// (2) Caller tries to get the code hash of a non-existent account, state should
|
||||
//
|
||||
// return common.Hash{} and zero will be set as the result.
|
||||
//
|
||||
// (3) Caller tries to get the code hash for an account without contract code,
|
||||
// (3) Caller tries to get the code hash for an account without contract code,
|
||||
//
|
||||
// state should return emptyCodeHash(0xc5d246...) as the result.
|
||||
//
|
||||
// (4) Caller tries to get the code hash of a precompiled account, the result
|
||||
// (4) Caller tries to get the code hash of a precompiled account, the result
|
||||
//
|
||||
// should be zero or emptyCodeHash.
|
||||
//
|
||||
// It is worth noting that in order to avoid unnecessary create and clean,
|
||||
|
|
@ -410,10 +415,12 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
|||
// If the precompile account is not transferred any amount on a private or
|
||||
// customized chain, the return value will be zero.
|
||||
//
|
||||
// (5) Caller tries to get the code hash for an account which is marked as suicided
|
||||
// (5) Caller tries to get the code hash for an account which is marked as suicided
|
||||
//
|
||||
// in the current transaction, the code hash of this account should be returned.
|
||||
//
|
||||
// (6) Caller tries to get the code hash for an account which is marked as deleted,
|
||||
// (6) Caller tries to get the code hash for an account which is marked as deleted,
|
||||
//
|
||||
// this account should be regarded as a non-existent account and zero should be returned.
|
||||
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||
slot := scope.Stack.peek()
|
||||
|
|
@ -688,7 +695,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
|||
bigVal = value.ToBig()
|
||||
}
|
||||
|
||||
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, bigVal)
|
||||
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, bigVal, nil)
|
||||
|
||||
if err != nil {
|
||||
temp.Clear()
|
||||
|
|
|
|||
|
|
@ -17,11 +17,33 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"hash"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
var (
|
||||
opcodeCommitInterruptCounter = metrics.NewRegisteredCounter("worker/opcodeCommitInterrupt", nil)
|
||||
ErrInterrupt = errors.New("EVM execution interrupted")
|
||||
ErrNoCache = errors.New("no tx cache found")
|
||||
ErrNoCurrentTx = errors.New("no current tx found in interruptCtx")
|
||||
)
|
||||
|
||||
const (
|
||||
// These are keys for the interruptCtx
|
||||
InterruptCtxDelayKey = "delay"
|
||||
InterruptCtxOpcodeDelayKey = "opcodeDelay"
|
||||
|
||||
// InterruptedTxCacheSize is size of lru cache for interrupted txs
|
||||
InterruptedTxCacheSize = 90000
|
||||
)
|
||||
|
||||
// Config are the configuration options for the Interpreter
|
||||
|
|
@ -68,6 +90,54 @@ type EVMInterpreter struct {
|
|||
returnData []byte // Last CALL's return data for subsequent reuse
|
||||
}
|
||||
|
||||
// TxCacher is an wrapper of lru.cache for caching transactions that get interrupted
|
||||
type TxCache struct {
|
||||
Cache *lru.Cache
|
||||
}
|
||||
|
||||
type txCacheKey struct{}
|
||||
type InterruptedTxContext_currenttxKey struct{}
|
||||
|
||||
// SetCurrentTxOnContext sets the current tx on the context
|
||||
func SetCurrentTxOnContext(ctx context.Context, txHash common.Hash) context.Context {
|
||||
return context.WithValue(ctx, InterruptedTxContext_currenttxKey{}, txHash)
|
||||
}
|
||||
|
||||
// GetCurrentTxFromContext gets the current tx from the context
|
||||
func GetCurrentTxFromContext(ctx context.Context) (common.Hash, error) {
|
||||
val := ctx.Value(InterruptedTxContext_currenttxKey{})
|
||||
if val == nil {
|
||||
return common.Hash{}, ErrNoCurrentTx
|
||||
}
|
||||
|
||||
c, ok := val.(common.Hash)
|
||||
if !ok {
|
||||
return common.Hash{}, ErrNoCurrentTx
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// GetCache returns the txCache from the context
|
||||
func GetCache(ctx context.Context) (*TxCache, error) {
|
||||
val := ctx.Value(txCacheKey{})
|
||||
if val == nil {
|
||||
return nil, ErrNoCache
|
||||
}
|
||||
|
||||
c, ok := val.(*TxCache)
|
||||
if !ok {
|
||||
return nil, ErrNoCache
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// PutCache puts the txCache into the context
|
||||
func PutCache(ctx context.Context, cache *TxCache) context.Context {
|
||||
return context.WithValue(ctx, txCacheKey{}, cache)
|
||||
}
|
||||
|
||||
// NewEVMInterpreter returns a new instance of the Interpreter.
|
||||
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
|
||||
// If jump table was not initialised we set the default one.
|
||||
|
|
@ -111,14 +181,192 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
|
|||
}
|
||||
}
|
||||
|
||||
// PreRun is a wrapper around Run that allows for a delay to be injected before each opcode when induced by tests else it calls the lagace Run() method
|
||||
func (in *EVMInterpreter) PreRun(contract *Contract, input []byte, readOnly bool, interruptCtx context.Context) (ret []byte, err error) {
|
||||
var opcodeDelay interface{}
|
||||
|
||||
if interruptCtx != nil {
|
||||
if interruptCtx.Value(InterruptCtxOpcodeDelayKey) != nil {
|
||||
opcodeDelay = interruptCtx.Value(InterruptCtxOpcodeDelayKey)
|
||||
}
|
||||
}
|
||||
|
||||
if opcodeDelay != nil {
|
||||
return in.RunWithDelay(contract, input, readOnly, interruptCtx, opcodeDelay.(uint))
|
||||
}
|
||||
|
||||
return in.Run(contract, input, readOnly, interruptCtx)
|
||||
}
|
||||
|
||||
// Run loops and evaluates the contract's code with the given input data and returns
|
||||
// the return byte-slice and an error if one occurred.
|
||||
//
|
||||
// It's important to note that any errors returned by the interpreter should be
|
||||
// considered a revert-and-consume-all-gas operation except for
|
||||
// ErrExecutionReverted which means revert-and-keep-gas-left.
|
||||
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
|
||||
// nolint: gocognit
|
||||
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool, interruptCtx context.Context) (ret []byte, err error) {
|
||||
// Increment the call depth which is restricted to 1024
|
||||
in.evm.depth++
|
||||
defer func() { in.evm.depth-- }()
|
||||
|
||||
// Make sure the readOnly is only set if we aren't in readOnly yet.
|
||||
// This also makes sure that the readOnly flag isn't removed for child calls.
|
||||
if readOnly && !in.readOnly {
|
||||
in.readOnly = true
|
||||
defer func() { in.readOnly = false }()
|
||||
}
|
||||
|
||||
// Reset the previous call's return data. It's unimportant to preserve the old buffer
|
||||
// as every returning call will return new data anyway.
|
||||
in.returnData = nil
|
||||
|
||||
// Don't bother with the execution if there's no code.
|
||||
if len(contract.Code) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var (
|
||||
op OpCode // current opcode
|
||||
mem = NewMemory() // bound memory
|
||||
stack = newstack() // local stack
|
||||
callContext = &ScopeContext{
|
||||
Memory: mem,
|
||||
Stack: stack,
|
||||
Contract: contract,
|
||||
}
|
||||
// For optimisation reason we're using uint64 as the program counter.
|
||||
// It's theoretically possible to go above 2^64. The YP defines the PC
|
||||
// to be uint256. Practically much less so feasible.
|
||||
pc = uint64(0) // program counter
|
||||
cost uint64
|
||||
// copies used by tracer
|
||||
pcCopy uint64 // needed for the deferred EVMLogger
|
||||
gasCopy uint64 // for EVMLogger to log gas remaining before execution
|
||||
logged bool // deferred EVMLogger should ignore already logged steps
|
||||
res []byte // result of the opcode execution function
|
||||
)
|
||||
// Don't move this deferrred function, it's placed before the capturestate-deferred method,
|
||||
// so that it get's executed _after_: the capturestate needs the stacks before
|
||||
// they are returned to the pools
|
||||
defer func() {
|
||||
returnStack(stack)
|
||||
}()
|
||||
|
||||
contract.Input = input
|
||||
|
||||
if in.cfg.Debug {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if !logged {
|
||||
in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||
} else {
|
||||
in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
// The Interpreter main run loop (contextual). This loop runs until either an
|
||||
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
|
||||
// the execution of one of the operations or until the done flag is set by the
|
||||
// parent context.
|
||||
for {
|
||||
if interruptCtx != nil {
|
||||
// case of interrupting by timeout
|
||||
select {
|
||||
case <-interruptCtx.Done():
|
||||
txHash, _ := GetCurrentTxFromContext(interruptCtx)
|
||||
interruptedTxCache, _ := GetCache(interruptCtx)
|
||||
|
||||
// if the tx is already in the cache, it means that it has been interrupted before and we will not interrupt it again
|
||||
found, _ := interruptedTxCache.Cache.ContainsOrAdd(txHash, true)
|
||||
if found {
|
||||
interruptedTxCache.Cache.Remove(txHash)
|
||||
} else {
|
||||
// if the tx is not in the cache, it means that it has not been interrupted before and we will interrupt it
|
||||
opcodeCommitInterruptCounter.Inc(1)
|
||||
log.Warn("OPCODE Level interrupt")
|
||||
|
||||
return nil, ErrInterrupt
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if in.cfg.Debug {
|
||||
// Capture pre-execution values for tracing.
|
||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||
}
|
||||
// Get the operation from the jump table and validate the stack to ensure there are
|
||||
// enough stack items available to perform the operation.
|
||||
op = contract.GetOp(pc)
|
||||
operation := in.cfg.JumpTable[op]
|
||||
cost = operation.constantGas // For tracing
|
||||
// Validate stack
|
||||
if sLen := stack.len(); sLen < operation.minStack {
|
||||
return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
|
||||
} else if sLen > operation.maxStack {
|
||||
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
|
||||
}
|
||||
|
||||
if !contract.UseGas(cost) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
// nolint : nestif
|
||||
if operation.dynamicGas != nil {
|
||||
// All ops with a dynamic memory usage also has a dynamic gas cost.
|
||||
var memorySize uint64
|
||||
// calculate the new memory size and expand the memory to fit
|
||||
// the operation
|
||||
// Memory check needs to be done prior to evaluating the dynamic gas portion,
|
||||
// to detect calculation overflows
|
||||
if operation.memorySize != nil {
|
||||
memSize, overflow := operation.memorySize(stack)
|
||||
if overflow {
|
||||
return nil, ErrGasUintOverflow
|
||||
}
|
||||
// memory is expanded in words of 32 bytes. Gas
|
||||
// is also calculated in words.
|
||||
if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
|
||||
return nil, ErrGasUintOverflow
|
||||
}
|
||||
}
|
||||
// Consume the gas and return an error if not enough gas is available.
|
||||
// cost is explicitly set so that the capture state defer method can get the proper cost
|
||||
var dynamicCost uint64
|
||||
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
|
||||
cost += dynamicCost // for tracing
|
||||
if err != nil || !contract.UseGas(dynamicCost) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
}
|
||||
}
|
||||
|
||||
if in.cfg.Debug {
|
||||
in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||
|
||||
logged = true
|
||||
}
|
||||
// execute the operation
|
||||
res, err = operation.execute(&pc, in, callContext)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
if err == errStopToken {
|
||||
err = nil // clear stop token error
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// nolint: gocognit
|
||||
// RunWithDelay is Run() with a delay between each opcode. Only used by testcases.
|
||||
func (in *EVMInterpreter) RunWithDelay(contract *Contract, input []byte, readOnly bool, interruptCtx context.Context, opcodeDelay uint) (ret []byte, err error) {
|
||||
// Increment the call depth which is restricted to 1024
|
||||
in.evm.depth++
|
||||
defer func() { in.evm.depth-- }()
|
||||
|
|
@ -183,6 +431,31 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
// the execution of one of the operations or until the done flag is set by the
|
||||
// parent context.
|
||||
for {
|
||||
if interruptCtx != nil {
|
||||
// case of interrupting by timeout
|
||||
select {
|
||||
case <-interruptCtx.Done():
|
||||
txHash, _ := GetCurrentTxFromContext(interruptCtx)
|
||||
interruptedTxCache, _ := GetCache(interruptCtx)
|
||||
// if the tx is already in the cache, it means that it has been interrupted before and we will not interrupt it again
|
||||
found, _ := interruptedTxCache.Cache.ContainsOrAdd(txHash, true)
|
||||
log.Info("FOUND", "found", found, "txHash", txHash)
|
||||
|
||||
if found {
|
||||
interruptedTxCache.Cache.Remove(txHash)
|
||||
} else {
|
||||
// if the tx is not in the cache, it means that it has not been interrupted before and we will interrupt it
|
||||
opcodeCommitInterruptCounter.Inc(1)
|
||||
log.Warn("OPCODE Level interrupt")
|
||||
|
||||
return nil, ErrInterrupt
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Duration(opcodeDelay) * time.Millisecond)
|
||||
|
||||
if in.cfg.Debug {
|
||||
// Capture pre-execution values for tracing.
|
||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ func TestLoopInterrupt(t *testing.T) {
|
|||
timeout := make(chan bool)
|
||||
|
||||
go func(evm *EVM) {
|
||||
_, _, err := evm.Call(AccountRef(common.Address{}), address, nil, math.MaxUint64, new(big.Int))
|
||||
_, _, err := evm.Call(AccountRef(common.Address{}), address, nil, math.MaxUint64, new(big.Int), nil)
|
||||
errChannel <- err
|
||||
}(evm)
|
||||
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
|||
input,
|
||||
cfg.GasLimit,
|
||||
cfg.Value,
|
||||
nil,
|
||||
)
|
||||
|
||||
return ret, cfg.State, err
|
||||
|
|
@ -186,6 +187,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
|
|||
input,
|
||||
cfg.GasLimit,
|
||||
cfg.Value,
|
||||
nil,
|
||||
)
|
||||
return ret, leftOverGas, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -386,12 +386,15 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
|
|||
//cfg.State.CreateAccount(cfg.Origin)
|
||||
// set the receiver's (the executing contract) code for execution.
|
||||
cfg.State.SetCode(destination, code)
|
||||
vmenv.Call(sender, destination, nil, gas, cfg.Value)
|
||||
|
||||
// nolint: errcheck
|
||||
vmenv.Call(sender, destination, nil, gas, cfg.Value, nil)
|
||||
|
||||
b.Run(name, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
vmenv.Call(sender, destination, nil, gas, cfg.Value)
|
||||
// nolint: errcheck
|
||||
vmenv.Call(sender, destination, nil, gas, cfg.Value, nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,4 @@
|
|||
|
||||
- ```save-key```: path to save the ecdsa private key
|
||||
|
||||
- ```dry-run```: validates parameters and prints bootnode configurations, but does not start bootnode (default: false)
|
||||
- ```dry-run```: validates parameters and prints bootnode configurations, but does not start bootnode (default: false)
|
||||
|
|
|
|||
|
|
@ -10,4 +10,4 @@ The ```debug pprof <enode>``` command will create an archive containing bor ppro
|
|||
|
||||
- ```output```: Output directory
|
||||
|
||||
- ```skiptrace```: Skip running the trace (default: false)
|
||||
- ```skiptrace```: Skip running the trace (default: false)
|
||||
|
|
|
|||
|
|
@ -101,9 +101,9 @@ devfakeauthor = false # Run miner without validator set authorization
|
|||
ep-requesttimeout = "0s" # Request Timeout for rpc execution pool for WS requests (default: 0s, 0s = disabled)
|
||||
[jsonrpc.graphql]
|
||||
enabled = false # Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.
|
||||
port = 0 #
|
||||
prefix = "" #
|
||||
host = "" #
|
||||
port = 0 #
|
||||
prefix = "" #
|
||||
host = "" #
|
||||
vhosts = ["localhost"] # Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
|
||||
corsdomain = ["localhost"] # Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
||||
[jsonrpc.auth]
|
||||
|
|
|
|||
|
|
@ -477,10 +477,21 @@ func (f *BlockFetcher) loop() {
|
|||
}
|
||||
defer req.Close()
|
||||
|
||||
res := <-resCh
|
||||
res.Done <- nil
|
||||
timeout := time.NewTimer(2 * fetchTimeout) // 2x leeway before dropping the peer
|
||||
defer timeout.Stop()
|
||||
|
||||
f.FilterHeaders(peer, *res.Res.(*eth.BlockHeadersPacket), time.Now().Add(res.Time))
|
||||
select {
|
||||
case res := <-resCh:
|
||||
res.Done <- nil
|
||||
f.FilterHeaders(peer, *res.Res.(*eth.BlockHeadersPacket), time.Now().Add(res.Time))
|
||||
|
||||
case <-timeout.C:
|
||||
// The peer didn't respond in time. The request
|
||||
// was already rescheduled at this point, we were
|
||||
// waiting for a catchup. With an unresponsive
|
||||
// peer however, it's a protocol violation.
|
||||
f.dropPeer(peer)
|
||||
}
|
||||
}(hash)
|
||||
}
|
||||
}(peer)
|
||||
|
|
@ -523,11 +534,23 @@ func (f *BlockFetcher) loop() {
|
|||
}
|
||||
defer req.Close()
|
||||
|
||||
res := <-resCh
|
||||
res.Done <- nil
|
||||
timeout := time.NewTimer(2 * fetchTimeout) // 2x leeway before dropping the peer
|
||||
defer timeout.Stop()
|
||||
|
||||
txs, uncles := res.Res.(*eth.BlockBodiesPacket).Unpack()
|
||||
f.FilterBodies(peer, txs, uncles, time.Now())
|
||||
select {
|
||||
case res := <-resCh:
|
||||
res.Done <- nil
|
||||
|
||||
txs, uncles := res.Res.(*eth.BlockBodiesPacket).Unpack()
|
||||
f.FilterBodies(peer, txs, uncles, time.Now())
|
||||
|
||||
case <-timeout.C:
|
||||
// The peer didn't respond in time. The request
|
||||
// was already rescheduled at this point, we were
|
||||
// waiting for a catchup. With an unresponsive
|
||||
// peer however, it's a protocol violation.
|
||||
f.dropPeer(peer)
|
||||
}
|
||||
}(peer, hashes)
|
||||
}
|
||||
// Schedule the next fetch if blocks are still pending
|
||||
|
|
|
|||
|
|
@ -193,9 +193,11 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec
|
|||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
|
||||
statedb.Prepare(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()), nil); err != nil {
|
||||
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||
}
|
||||
|
||||
// Ensure any modifications are committed to the state
|
||||
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
||||
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||
|
|
|
|||
|
|
@ -654,7 +654,8 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
|||
break
|
||||
}
|
||||
} else {
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
||||
// nolint : contextcheck
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background()); err != nil {
|
||||
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
||||
// We intentionally don't return the error here: if we do, then the RPC server will not
|
||||
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
||||
|
|
@ -833,7 +834,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||
break
|
||||
}
|
||||
} else {
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background()); err != nil {
|
||||
failed = err
|
||||
break
|
||||
}
|
||||
|
|
@ -844,7 +845,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||
} else {
|
||||
coinbaseBalance := statedb.GetBalance(blockCtx.Coinbase)
|
||||
|
||||
result, err := core.ApplyMessageNoFeeBurnOrTip(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
||||
result, err := core.ApplyMessageNoFeeBurnOrTip(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background())
|
||||
|
||||
if err != nil {
|
||||
failed = err
|
||||
|
|
@ -1036,7 +1037,8 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
|||
}
|
||||
}
|
||||
} else {
|
||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
||||
// nolint : contextcheck
|
||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background())
|
||||
if writer != nil {
|
||||
writer.Flush()
|
||||
}
|
||||
|
|
@ -1248,7 +1250,8 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex
|
|||
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||
}
|
||||
} else {
|
||||
result, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
|
||||
// nolint : contextcheck
|
||||
result, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T
|
|||
callmsg := prepareCallMessage(message)
|
||||
execRes, err = statefull.ApplyBorMessage(*vmenv, callmsg)
|
||||
} else {
|
||||
execRes, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
|
||||
execRes, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), nil)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -167,14 +167,17 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
|||
for idx, tx := range block.Transactions() {
|
||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
||||
blockContext := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
||||
if idx == txIndex {
|
||||
return msg, context, statedb, nil
|
||||
return msg, blockContext, statedb, nil
|
||||
}
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
||||
|
||||
vmenv := vm.NewEVM(blockContext, txContext, statedb, b.chainConfig, vm.Config{})
|
||||
// nolint : contextcheck
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), context.Background()); err != nil {
|
||||
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||
}
|
||||
|
||||
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||
}
|
||||
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package tracetest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
|
|
@ -168,7 +169,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
Origin: origin,
|
||||
GasPrice: tx.GasPrice(),
|
||||
}
|
||||
context = vm.BlockContext{
|
||||
blockContext = vm.BlockContext{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
Coinbase: test.Context.Miner,
|
||||
|
|
@ -183,13 +184,13 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||
evm := vm.NewEVM(blockContext, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||
msg, err := tx.AsMessage(signer, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
}
|
||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if _, err = st.TransitionDb(); err != nil {
|
||||
if _, err = st.TransitionDb(context.Background()); err != nil {
|
||||
t.Fatalf("failed to execute transaction: %v", err)
|
||||
}
|
||||
// Retrieve the trace result and compare against the etalon
|
||||
|
|
@ -279,7 +280,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
|||
Origin: origin,
|
||||
GasPrice: tx.GasPrice(),
|
||||
}
|
||||
context := vm.BlockContext{
|
||||
blockContext := vm.BlockContext{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
Coinbase: test.Context.Miner,
|
||||
|
|
@ -297,15 +298,19 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
|||
if err != nil {
|
||||
b.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||
|
||||
evm := vm.NewEVM(blockContext, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||
snap := statedb.Snapshot()
|
||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if _, err = st.TransitionDb(); err != nil {
|
||||
|
||||
if _, err = st.TransitionDb(context.Background()); err != nil {
|
||||
b.Fatalf("failed to execute transaction: %v", err)
|
||||
}
|
||||
|
||||
if _, err = tracer.GetResult(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
statedb.RevertToSnapshot(snap)
|
||||
}
|
||||
}
|
||||
|
|
@ -333,7 +338,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
|
|||
Origin: origin,
|
||||
GasPrice: big.NewInt(1),
|
||||
}
|
||||
context := vm.BlockContext{
|
||||
blockContext := vm.BlockContext{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
Coinbase: common.Address{},
|
||||
|
|
@ -363,15 +368,18 @@ func TestZeroValueToNotExitCall(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||
|
||||
evm := vm.NewEVM(blockContext, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||
msg, err := tx.AsMessage(signer, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
}
|
||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if _, err = st.TransitionDb(); err != nil {
|
||||
|
||||
if _, err = st.TransitionDb(context.Background()); err != nil {
|
||||
t.Fatalf("failed to execute transaction: %v", err)
|
||||
}
|
||||
|
||||
// Retrieve the trace result and compare against the etalon
|
||||
res, err := tracer.GetResult()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
|
|||
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
|
||||
|
||||
tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
|
||||
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
||||
ret, err := env.Interpreter().Run(contract, []byte{}, false, nil)
|
||||
tracer.CaptureEnd(ret, startGas-contract.Gas, 1, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func TestStoreCapture(t *testing.T) {
|
|||
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
|
||||
var index common.Hash
|
||||
logger.CaptureStart(env, common.Address{}, contract.Address(), false, nil, 0, nil)
|
||||
_, err := env.Interpreter().Run(contract, []byte{}, false)
|
||||
_, err := env.Interpreter().PreRun(contract, []byte{}, false, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package tracers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
|||
Origin: from,
|
||||
GasPrice: tx.GasPrice(),
|
||||
}
|
||||
context := vm.BlockContext{
|
||||
blockContext := vm.BlockContext{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
Coinbase: common.Address{},
|
||||
|
|
@ -102,7 +103,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
|||
//EnableMemory: false,
|
||||
//EnableReturnData: false,
|
||||
})
|
||||
evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer})
|
||||
evm := vm.NewEVM(blockContext, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer})
|
||||
msg, err := tx.AsMessage(signer, nil)
|
||||
if err != nil {
|
||||
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
|
|
@ -113,7 +114,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
snap := statedb.Snapshot()
|
||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
_, err = st.TransitionDb()
|
||||
_, err = st.TransitionDb(context.Background())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,8 +306,9 @@ type SealerConfig struct {
|
|||
GasPriceRaw string `hcl:"gasprice,optional" toml:"gasprice,optional"`
|
||||
|
||||
// The time interval for miner to re-create mining work.
|
||||
Recommit time.Duration `hcl:"-,optional" toml:"-"`
|
||||
RecommitRaw string `hcl:"recommit,optional" toml:"recommit,optional"`
|
||||
Recommit time.Duration `hcl:"-,optional" toml:"-"`
|
||||
RecommitRaw string `hcl:"recommit,optional" toml:"recommit,optional"`
|
||||
CommitInterruptFlag bool `hcl:"commitinterrupt,optional" toml:"commitinterrupt,optional"`
|
||||
}
|
||||
|
||||
type JsonRPCConfig struct {
|
||||
|
|
@ -630,12 +631,13 @@ func DefaultConfig() *Config {
|
|||
LifeTime: 3 * time.Hour,
|
||||
},
|
||||
Sealer: &SealerConfig{
|
||||
Enabled: false,
|
||||
Etherbase: "",
|
||||
GasCeil: 30_000_000, // geth's default
|
||||
GasPrice: big.NewInt(1 * params.GWei), // geth's default
|
||||
ExtraData: "",
|
||||
Recommit: 125 * time.Second,
|
||||
Enabled: false,
|
||||
Etherbase: "",
|
||||
GasCeil: 30_000_000, // geth's default
|
||||
GasPrice: big.NewInt(1 * params.GWei), // geth's default
|
||||
ExtraData: "",
|
||||
Recommit: 125 * time.Second,
|
||||
CommitInterruptFlag: true,
|
||||
},
|
||||
Gpo: &GpoConfig{
|
||||
Blocks: 20,
|
||||
|
|
@ -928,6 +930,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
n.Miner.GasPrice = c.Sealer.GasPrice
|
||||
n.Miner.GasCeil = c.Sealer.GasCeil
|
||||
n.Miner.ExtraData = []byte(c.Sealer.ExtraData)
|
||||
n.Miner.CommitInterruptFlag = c.Sealer.CommitInterruptFlag
|
||||
|
||||
if etherbase := c.Sealer.Etherbase; etherbase != "" {
|
||||
if !common.IsHexAddress(etherbase) {
|
||||
|
|
|
|||
|
|
@ -302,6 +302,13 @@ func (c *Command) Flags() *flagset.Flagset {
|
|||
Default: c.cliConfig.Sealer.Recommit,
|
||||
Group: "Sealer",
|
||||
})
|
||||
f.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "miner.interruptcommit",
|
||||
Usage: "Interrupt block commit when block creation time is passed",
|
||||
Value: &c.cliConfig.Sealer.CommitInterruptFlag,
|
||||
Default: c.cliConfig.Sealer.CommitInterruptFlag,
|
||||
Group: "Sealer",
|
||||
})
|
||||
|
||||
// ethstats
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
|
|
|
|||
|
|
@ -1027,7 +1027,8 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
|||
|
||||
// Execute the message.
|
||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
result, err := core.ApplyMessage(evm, msg, gp)
|
||||
// nolint : contextcheck
|
||||
result, err := core.ApplyMessage(evm, msg, gp, context.Background())
|
||||
if err := vmError(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1595,13 +1596,16 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
|||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
||||
// nolint : contextcheck
|
||||
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background())
|
||||
if err != nil {
|
||||
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
||||
}
|
||||
|
||||
if tracer.Equal(prevTracer) {
|
||||
return accessList, res.UsedGas, res.Err, nil
|
||||
}
|
||||
|
||||
prevTracer = tracer
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,13 +137,14 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||
|
||||
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)}
|
||||
|
||||
context := core.NewEVMBlockContext(header, bc, nil)
|
||||
blockContext := core.NewEVMBlockContext(header, bc, nil)
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, config, vm.Config{NoBaseFee: true})
|
||||
vmenv := vm.NewEVM(blockContext, txContext, statedb, config, vm.Config{NoBaseFee: true})
|
||||
|
||||
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
|
||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||
// nolint : contextcheck
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp, context.Background())
|
||||
res = append(res, result.Return()...)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -151,11 +152,12 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||
state := light.NewState(ctx, header, lc.Odr())
|
||||
state.SetBalance(bankAddr, math.MaxBig256)
|
||||
msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)}
|
||||
context := core.NewEVMBlockContext(header, lc, nil)
|
||||
blockContext := core.NewEVMBlockContext(header, lc, nil)
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true})
|
||||
vmenv := vm.NewEVM(blockContext, txContext, state, config, vm.Config{NoBaseFee: true})
|
||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||
// nolint : contextcheck
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp, context.Background())
|
||||
if state.Error() == nil {
|
||||
res = append(res, result.Return()...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,14 +57,15 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
|
|||
// Assemble the transaction call message and return if the requested offset
|
||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
||||
blockContext := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
||||
statedb.Prepare(tx.Hash(), idx)
|
||||
if idx == txIndex {
|
||||
return msg, context, statedb, nil
|
||||
return msg, blockContext, statedb, nil
|
||||
}
|
||||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{})
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
||||
vmenv := vm.NewEVM(blockContext, txContext, statedb, leth.blockchain.Config(), vm.Config{})
|
||||
// nolint : contextcheck
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), context.Background()); err != nil {
|
||||
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||
}
|
||||
// Ensure any modifications are committed to the state
|
||||
|
|
|
|||
|
|
@ -196,10 +196,11 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
|||
st.SetBalance(testBankAddress, math.MaxBig256)
|
||||
msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)}
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
context := core.NewEVMBlockContext(header, chain, nil)
|
||||
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
|
||||
blockContext := core.NewEVMBlockContext(header, chain, nil)
|
||||
vmenv := vm.NewEVM(blockContext, txContext, st, config, vm.Config{NoBaseFee: true})
|
||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||
// nolint : contextcheck
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp, context.Background())
|
||||
res = append(res, result.Return()...)
|
||||
if st.Error() != nil {
|
||||
return res, st.Error()
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ var (
|
|||
// Test accounts
|
||||
testBankKey, _ = crypto.GenerateKey()
|
||||
TestBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey)
|
||||
testBankFunds = big.NewInt(1000000000000000000)
|
||||
testBankFunds = big.NewInt(8000000000000000000)
|
||||
|
||||
testUserKey, _ = crypto.GenerateKey()
|
||||
testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey)
|
||||
|
|
@ -222,8 +222,9 @@ var (
|
|||
newTxs []*types.Transaction
|
||||
|
||||
testConfig = &Config{
|
||||
Recommit: time.Second,
|
||||
GasCeil: params.GenesisGasLimit,
|
||||
Recommit: time.Second,
|
||||
GasCeil: params.GenesisGasLimit,
|
||||
CommitInterruptFlag: true,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -45,15 +45,16 @@ type Backend interface {
|
|||
|
||||
// Config is the configuration parameters of mining.
|
||||
type Config struct {
|
||||
Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards (default = first account)
|
||||
Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash).
|
||||
NotifyFull bool `toml:",omitempty"` // Notify with pending block headers instead of work packages
|
||||
ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner
|
||||
GasFloor uint64 // Target gas floor for mined blocks.
|
||||
GasCeil uint64 // Target gas ceiling for mined blocks.
|
||||
GasPrice *big.Int // Minimum gas price for mining a transaction
|
||||
Recommit time.Duration // The time interval for miner to re-create mining work.
|
||||
Noverify bool // Disable remote mining solution verification(only useful in ethash).
|
||||
Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards (default = first account)
|
||||
Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash).
|
||||
NotifyFull bool `toml:",omitempty"` // Notify with pending block headers instead of work packages
|
||||
ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner
|
||||
GasFloor uint64 // Target gas floor for mined blocks.
|
||||
GasCeil uint64 // Target gas ceiling for mined blocks.
|
||||
GasPrice *big.Int // Minimum gas price for mining a transaction
|
||||
Recommit time.Duration // The time interval for miner to re-create mining work.
|
||||
Noverify bool // Disable remote mining solution verification(only useful in ethash).
|
||||
CommitInterruptFlag bool // Interrupt commit when time is up ( default = true)
|
||||
}
|
||||
|
||||
// Miner creates blocks and searches for proof-of-work values.
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import (
|
|||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -40,6 +42,10 @@ const (
|
|||
|
||||
// testGas is the gas required for contract deployment.
|
||||
testGas = 144109
|
||||
|
||||
storageContractByteCode = "608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea2646970667358221220322c78243e61b783558509c9cc22cb8493dde6925aa5e89a08cdf6e22f279ef164736f6c63430008120033"
|
||||
storageContractTxCallData = "0x6057361d0000000000000000000000000000000000000000000000000000000000000001"
|
||||
storageCallTxGas = 100000
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -167,6 +173,7 @@ func (b *testWorkerBackend) newRandomUncle() (*types.Block, error) {
|
|||
return blocks[0], err
|
||||
}
|
||||
|
||||
// newRandomTx creates a new transaction.
|
||||
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
||||
var tx *types.Transaction
|
||||
|
||||
|
|
@ -181,15 +188,54 @@ func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
|||
return tx
|
||||
}
|
||||
|
||||
func NewTestWorker(t TensingObject, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int, noempty uint32, delay uint) (*worker, *testWorkerBackend, func()) {
|
||||
// newRandomTxWithNonce creates a new transaction with the given nonce.
|
||||
func (b *testWorkerBackend) newRandomTxWithNonce(creation bool, nonce uint64) *types.Transaction {
|
||||
var tx *types.Transaction
|
||||
|
||||
gasPrice := big.NewInt(100 * params.InitialBaseFee)
|
||||
|
||||
if creation {
|
||||
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(TestBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
|
||||
} else {
|
||||
tx, _ = types.SignTx(types.NewTransaction(nonce, testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey)
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
// newRandomTxWithGas creates a new transactionto deploy a storage smart contract.
|
||||
func (b *testWorkerBackend) newStorageCreateContractTx() (*types.Transaction, common.Address) {
|
||||
var tx *types.Transaction
|
||||
|
||||
gasPrice := big.NewInt(10 * params.InitialBaseFee)
|
||||
|
||||
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(TestBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(storageContractByteCode)), types.HomesteadSigner{}, testBankKey)
|
||||
contractAddr := crypto.CreateAddress(TestBankAddress, b.txPool.Nonce(TestBankAddress))
|
||||
|
||||
return tx, contractAddr
|
||||
}
|
||||
|
||||
// newStorageContractCallTx creates a new transaction to call a storage smart contract.
|
||||
func (b *testWorkerBackend) newStorageContractCallTx(to common.Address, nonce uint64) *types.Transaction {
|
||||
var tx *types.Transaction
|
||||
|
||||
gasPrice := big.NewInt(10 * params.InitialBaseFee)
|
||||
|
||||
tx, _ = types.SignTx(types.NewTransaction(nonce, to, nil, storageCallTxGas, gasPrice, common.FromHex(storageContractTxCallData)), types.HomesteadSigner{}, testBankKey)
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
// NewTestWorker creates a new test worker with the given parameters.
|
||||
func NewTestWorker(t TensingObject, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int, noempty uint32, delay uint, opcodeDelay uint) (*worker, *testWorkerBackend, func()) {
|
||||
backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks)
|
||||
backend.txPool.AddLocals(pendingTxs)
|
||||
|
||||
var w *worker
|
||||
|
||||
if delay != 0 {
|
||||
if delay != 0 || opcodeDelay != 0 {
|
||||
//nolint:staticcheck
|
||||
w = newWorkerWithDelay(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false, delay)
|
||||
w = newWorkerWithDelay(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false, delay, opcodeDelay)
|
||||
} else {
|
||||
//nolint:staticcheck
|
||||
w = newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false)
|
||||
|
|
@ -203,32 +249,34 @@ func NewTestWorker(t TensingObject, chainConfig *params.ChainConfig, engine cons
|
|||
return w, backend, w.close
|
||||
}
|
||||
|
||||
//nolint:staticcheck
|
||||
func newWorkerWithDelay(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(header *types.Header) bool, init bool, delay uint) *worker {
|
||||
// newWorkerWithDelay is newWorker() with extra params to induce artficial delays for tests such as commit-interrupt.
|
||||
// nolint:staticcheck
|
||||
func newWorkerWithDelay(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(header *types.Header) bool, init bool, delay uint, opcodeDelay uint) *worker {
|
||||
worker := &worker{
|
||||
config: config,
|
||||
chainConfig: chainConfig,
|
||||
engine: engine,
|
||||
eth: eth,
|
||||
mux: mux,
|
||||
chain: eth.BlockChain(),
|
||||
isLocalBlock: isLocalBlock,
|
||||
localUncles: make(map[common.Hash]*types.Block),
|
||||
remoteUncles: make(map[common.Hash]*types.Block),
|
||||
unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), sealingLogAtDepth),
|
||||
pendingTasks: make(map[common.Hash]*task),
|
||||
txsCh: make(chan core.NewTxsEvent, txChanSize),
|
||||
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
||||
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
|
||||
newWorkCh: make(chan *newWorkReq),
|
||||
getWorkCh: make(chan *getWorkReq),
|
||||
taskCh: make(chan *task),
|
||||
resultCh: make(chan *types.Block, resultQueueSize),
|
||||
exitCh: make(chan struct{}),
|
||||
startCh: make(chan struct{}, 1),
|
||||
resubmitIntervalCh: make(chan time.Duration),
|
||||
resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
|
||||
noempty: 1,
|
||||
config: config,
|
||||
chainConfig: chainConfig,
|
||||
engine: engine,
|
||||
eth: eth,
|
||||
mux: mux,
|
||||
chain: eth.BlockChain(),
|
||||
isLocalBlock: isLocalBlock,
|
||||
localUncles: make(map[common.Hash]*types.Block),
|
||||
remoteUncles: make(map[common.Hash]*types.Block),
|
||||
unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), sealingLogAtDepth),
|
||||
pendingTasks: make(map[common.Hash]*task),
|
||||
txsCh: make(chan core.NewTxsEvent, txChanSize),
|
||||
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
||||
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
|
||||
newWorkCh: make(chan *newWorkReq),
|
||||
getWorkCh: make(chan *getWorkReq),
|
||||
taskCh: make(chan *task),
|
||||
resultCh: make(chan *types.Block, resultQueueSize),
|
||||
exitCh: make(chan struct{}),
|
||||
startCh: make(chan struct{}, 1),
|
||||
resubmitIntervalCh: make(chan time.Duration),
|
||||
resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
|
||||
noempty: 1,
|
||||
interruptCommitFlag: config.CommitInterruptFlag,
|
||||
}
|
||||
worker.profileCount = new(int32)
|
||||
// Subscribe NewTxsEvent for tx pool
|
||||
|
|
@ -237,6 +285,19 @@ func newWorkerWithDelay(config *Config, chainConfig *params.ChainConfig, engine
|
|||
worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh)
|
||||
worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh)
|
||||
|
||||
interruptedTxCache, err := lru.New(vm.InterruptedTxCacheSize)
|
||||
if err != nil {
|
||||
log.Warn("Failed to create interrupted tx cache", "err", err)
|
||||
}
|
||||
|
||||
worker.interruptedTxCache = &vm.TxCache{
|
||||
Cache: interruptedTxCache,
|
||||
}
|
||||
|
||||
if !worker.interruptCommitFlag {
|
||||
worker.noempty = 0
|
||||
}
|
||||
|
||||
// Sanitize recommit interval if the user-specified one is too short.
|
||||
recommit := worker.config.Recommit
|
||||
if recommit < minRecommitInterval {
|
||||
|
|
@ -248,7 +309,7 @@ func newWorkerWithDelay(config *Config, chainConfig *params.ChainConfig, engine
|
|||
|
||||
worker.wg.Add(4)
|
||||
|
||||
go worker.mainLoopWithDelay(ctx, delay)
|
||||
go worker.mainLoopWithDelay(ctx, delay, opcodeDelay)
|
||||
go worker.newWorkLoop(ctx, recommit)
|
||||
go worker.resultLoop()
|
||||
go worker.taskLoop()
|
||||
|
|
@ -261,8 +322,9 @@ func newWorkerWithDelay(config *Config, chainConfig *params.ChainConfig, engine
|
|||
return worker
|
||||
}
|
||||
|
||||
// mainLoopWithDelay is mainLoop() with extra params to induce artficial delays for tests such as commit-interrupt.
|
||||
// nolint:gocognit
|
||||
func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint) {
|
||||
func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint, opcodeDelay uint) {
|
||||
defer w.wg.Done()
|
||||
defer w.txsSub.Unsubscribe()
|
||||
defer w.chainHeadSub.Unsubscribe()
|
||||
|
|
@ -280,7 +342,7 @@ func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint) {
|
|||
select {
|
||||
case req := <-w.newWorkCh:
|
||||
//nolint:contextcheck
|
||||
w.commitWorkWithDelay(req.ctx, req.interrupt, req.noempty, req.timestamp, delay)
|
||||
w.commitWorkWithDelay(req.ctx, req.interrupt, req.noempty, req.timestamp, delay, opcodeDelay)
|
||||
|
||||
case req := <-w.getWorkCh:
|
||||
//nolint:contextcheck
|
||||
|
|
@ -342,6 +404,7 @@ func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint) {
|
|||
// Note all transactions received may not be continuous with transactions
|
||||
// already included in the current sealing block. These transactions will
|
||||
// be automatically eliminated.
|
||||
// nolint : nestif
|
||||
if !w.isRunning() && w.current != nil {
|
||||
// If block is already full, abort
|
||||
if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas {
|
||||
|
|
@ -358,8 +421,19 @@ func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint) {
|
|||
txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs, cmath.FromBig(w.current.header.BaseFee))
|
||||
tcount := w.current.tcount
|
||||
|
||||
interruptCh, stopFn := getInterruptTimer(ctx, w.current, w.chain.CurrentBlock())
|
||||
w.commitTransactionsWithDelay(w.current, txset, nil, interruptCh, delay)
|
||||
var interruptCtx = context.Background()
|
||||
stopFn := func() {}
|
||||
defer func() {
|
||||
stopFn()
|
||||
}()
|
||||
|
||||
if w.interruptCommitFlag {
|
||||
interruptCtx, stopFn = getInterruptTimer(ctx, w.current, w.chain.CurrentBlock())
|
||||
// nolint : staticcheck
|
||||
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache)
|
||||
}
|
||||
|
||||
w.commitTransactionsWithDelay(w.current, txset, nil, interruptCtx)
|
||||
|
||||
// Only update the snapshot if any new transactions were added
|
||||
// to the pending block
|
||||
|
|
@ -392,166 +466,8 @@ func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint) {
|
|||
}
|
||||
}
|
||||
|
||||
// nolint:gocognit
|
||||
func (w *worker) commitTransactionsWithDelay(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *int32, interruptCh chan struct{}, delay uint) bool {
|
||||
gasLimit := env.header.GasLimit
|
||||
if env.gasPool == nil {
|
||||
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||
}
|
||||
|
||||
var coalescedLogs []*types.Log
|
||||
|
||||
initialGasLimit := env.gasPool.Gas()
|
||||
initialTxs := txs.GetTxs()
|
||||
|
||||
var breakCause string
|
||||
|
||||
defer func() {
|
||||
log.OnDebug(func(lg log.Logging) {
|
||||
lg("commitTransactions-stats",
|
||||
"initialTxsCount", initialTxs,
|
||||
"initialGasLimit", initialGasLimit,
|
||||
"resultTxsCount", txs.GetTxs(),
|
||||
"resultGapPool", env.gasPool.Gas(),
|
||||
"exitCause", breakCause)
|
||||
})
|
||||
}()
|
||||
|
||||
mainloop:
|
||||
for {
|
||||
// case of interrupting by timeout
|
||||
select {
|
||||
case <-interruptCh:
|
||||
commitInterruptCounter.Inc(1)
|
||||
break mainloop
|
||||
default:
|
||||
}
|
||||
// In the following three cases, we will interrupt the execution of the transaction.
|
||||
// (1) new head block event arrival, the interrupt signal is 1
|
||||
// (2) worker start or restart, the interrupt signal is 1
|
||||
// (3) worker recreate the sealing block with any newly arrived transactions, the interrupt signal is 2.
|
||||
// For the first two cases, the semi-finished work will be discarded.
|
||||
// For the third case, the semi-finished work will be submitted to the consensus engine.
|
||||
if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone {
|
||||
// Notify resubmit loop to increase resubmitting interval due to too frequent commits.
|
||||
if atomic.LoadInt32(interrupt) == commitInterruptResubmit {
|
||||
ratio := float64(gasLimit-env.gasPool.Gas()) / float64(gasLimit)
|
||||
if ratio < 0.1 {
|
||||
// nolint:goconst
|
||||
ratio = 0.1
|
||||
}
|
||||
w.resubmitAdjustCh <- &intervalAdjust{
|
||||
ratio: ratio,
|
||||
inc: true,
|
||||
}
|
||||
}
|
||||
// nolint:goconst
|
||||
breakCause = "interrupt"
|
||||
return atomic.LoadInt32(interrupt) == commitInterruptNewHead
|
||||
}
|
||||
// If we don't have enough gas for any further transactions then we're done
|
||||
if env.gasPool.Gas() < params.TxGas {
|
||||
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
|
||||
// nolint:goconst
|
||||
breakCause = "Not enough gas for further transactions"
|
||||
break
|
||||
}
|
||||
// Retrieve the next transaction and abort if all done
|
||||
tx := txs.Peek()
|
||||
if tx == nil {
|
||||
// nolint:goconst
|
||||
breakCause = "all transactions has been included"
|
||||
break
|
||||
}
|
||||
// Error may be ignored here. The error has already been checked
|
||||
// during transaction acceptance is the transaction pool.
|
||||
//
|
||||
// We use the eip155 signer regardless of the current hf.
|
||||
from, _ := types.Sender(env.signer, tx)
|
||||
// Check whether the tx is replay protected. If we're not in the EIP155 hf
|
||||
// phase, start ignoring the sender until we do.
|
||||
if tx.Protected() && !w.chainConfig.IsEIP155(env.header.Number) {
|
||||
log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.chainConfig.EIP155Block)
|
||||
|
||||
txs.Pop()
|
||||
continue
|
||||
}
|
||||
// Start executing the transaction
|
||||
env.state.Prepare(tx.Hash(), env.tcount)
|
||||
|
||||
var start time.Time
|
||||
|
||||
log.OnDebug(func(log.Logging) {
|
||||
start = time.Now()
|
||||
})
|
||||
|
||||
logs, err := w.commitTransaction(env, tx)
|
||||
time.Sleep(time.Duration(delay) * time.Millisecond)
|
||||
|
||||
switch {
|
||||
case errors.Is(err, core.ErrGasLimitReached):
|
||||
// Pop the current out-of-gas transaction without shifting in the next from the account
|
||||
log.Trace("Gas limit exceeded for current block", "sender", from)
|
||||
txs.Pop()
|
||||
|
||||
case errors.Is(err, core.ErrNonceTooLow):
|
||||
// New head notification data race between the transaction pool and miner, shift
|
||||
log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce())
|
||||
txs.Shift()
|
||||
|
||||
case errors.Is(err, core.ErrNonceTooHigh):
|
||||
// Reorg notification data race between the transaction pool and miner, skip account =
|
||||
log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce())
|
||||
txs.Pop()
|
||||
|
||||
case errors.Is(err, nil):
|
||||
// Everything ok, collect the logs and shift in the next transaction from the same account
|
||||
coalescedLogs = append(coalescedLogs, logs...)
|
||||
env.tcount++
|
||||
txs.Shift()
|
||||
|
||||
log.OnDebug(func(lg log.Logging) {
|
||||
lg("Committed new tx", "tx hash", tx.Hash(), "from", from, "to", tx.To(), "nonce", tx.Nonce(), "gas", tx.Gas(), "gasPrice", tx.GasPrice(), "value", tx.Value(), "time spent", time.Since(start))
|
||||
})
|
||||
|
||||
case errors.Is(err, core.ErrTxTypeNotSupported):
|
||||
// Pop the unsupported transaction without shifting in the next from the account
|
||||
log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type())
|
||||
txs.Pop()
|
||||
|
||||
default:
|
||||
// Strange error, discard the transaction and get the next in line (note, the
|
||||
// nonce-too-high clause will prevent us from executing in vain).
|
||||
log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err)
|
||||
txs.Shift()
|
||||
}
|
||||
}
|
||||
|
||||
if !w.isRunning() && len(coalescedLogs) > 0 {
|
||||
// We don't push the pendingLogsEvent while we are sealing. The reason is that
|
||||
// when we are sealing, the worker will regenerate a sealing block every 3 seconds.
|
||||
// In order to avoid pushing the repeated pendingLog, we disable the pending log pushing.
|
||||
// make a copy, the state caches the logs and these logs get "upgraded" from pending to mined
|
||||
// logs by filling in the block hash when the block was mined by the local miner. This can
|
||||
// cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed.
|
||||
cpy := make([]*types.Log, len(coalescedLogs))
|
||||
for i, l := range coalescedLogs {
|
||||
cpy[i] = new(types.Log)
|
||||
*cpy[i] = *l
|
||||
}
|
||||
|
||||
w.pendingLogsFeed.Send(cpy)
|
||||
}
|
||||
// Notify resubmit loop to decrease resubmitting interval if current interval is larger
|
||||
// than the user-specified one.
|
||||
if interrupt != nil {
|
||||
w.resubmitAdjustCh <- &intervalAdjust{inc: false}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *int32, noempty bool, timestamp int64, delay uint) {
|
||||
// commitWorkWithDelay is commitWork() with extra params to induce artficial delays for tests such as commit-interrupt.
|
||||
func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *int32, noempty bool, timestamp int64, delay uint, opcodeDelay uint) {
|
||||
start := time.Now()
|
||||
|
||||
var (
|
||||
|
|
@ -581,15 +497,22 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *int32, noem
|
|||
return
|
||||
}
|
||||
|
||||
var interruptCh chan struct{}
|
||||
// nolint : contextcheck
|
||||
var interruptCtx = context.Background()
|
||||
|
||||
stopFn := func() {}
|
||||
defer func() {
|
||||
stopFn()
|
||||
}()
|
||||
|
||||
if !noempty {
|
||||
interruptCh, stopFn = getInterruptTimer(ctx, work, w.chain.CurrentBlock())
|
||||
if !noempty && w.interruptCommitFlag {
|
||||
interruptCtx, stopFn = getInterruptTimer(ctx, work, w.chain.CurrentBlock())
|
||||
// nolint : staticcheck
|
||||
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache)
|
||||
// nolint : staticcheck
|
||||
interruptCtx = context.WithValue(interruptCtx, vm.InterruptCtxDelayKey, delay)
|
||||
// nolint : staticcheck
|
||||
interruptCtx = context.WithValue(interruptCtx, vm.InterruptCtxOpcodeDelayKey, opcodeDelay)
|
||||
}
|
||||
|
||||
ctx, span := tracing.StartSpan(ctx, "commitWork")
|
||||
|
|
@ -610,7 +533,7 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *int32, noem
|
|||
}
|
||||
|
||||
// Fill pending transactions from the txpool
|
||||
w.fillTransactionsWithDelay(ctx, interrupt, work, interruptCh, delay)
|
||||
w.fillTransactionsWithDelay(ctx, interrupt, work, interruptCtx)
|
||||
|
||||
err = w.commit(ctx, work.copy(), w.fullTaskHook, true, start)
|
||||
if err != nil {
|
||||
|
|
@ -626,8 +549,9 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *int32, noem
|
|||
w.current = work
|
||||
}
|
||||
|
||||
// fillTransactionsWithDelay is fillTransactions() with extra params to induce artficial delays for tests such as commit-interrupt.
|
||||
// nolint:gocognit
|
||||
func (w *worker) fillTransactionsWithDelay(ctx context.Context, interrupt *int32, env *environment, interruptCh chan struct{}, delay uint) {
|
||||
func (w *worker) fillTransactionsWithDelay(ctx context.Context, interrupt *int32, env *environment, interruptCtx context.Context) {
|
||||
ctx, span := tracing.StartSpan(ctx, "fillTransactions")
|
||||
defer tracing.EndSpan(span)
|
||||
|
||||
|
|
@ -751,7 +675,7 @@ func (w *worker) fillTransactionsWithDelay(ctx context.Context, interrupt *int32
|
|||
})
|
||||
|
||||
tracing.Exec(ctx, "", "worker.LocalCommitTransactions", func(ctx context.Context, span trace.Span) {
|
||||
committed = w.commitTransactionsWithDelay(env, txs, interrupt, interruptCh, delay)
|
||||
committed = w.commitTransactionsWithDelay(env, txs, interrupt, interruptCtx)
|
||||
})
|
||||
|
||||
if committed {
|
||||
|
|
@ -774,7 +698,7 @@ func (w *worker) fillTransactionsWithDelay(ctx context.Context, interrupt *int32
|
|||
})
|
||||
|
||||
tracing.Exec(ctx, "", "worker.RemoteCommitTransactions", func(ctx context.Context, span trace.Span) {
|
||||
committed = w.commitTransactionsWithDelay(env, txs, interrupt, interruptCh, delay)
|
||||
committed = w.commitTransactionsWithDelay(env, txs, interrupt, interruptCtx)
|
||||
})
|
||||
|
||||
if committed {
|
||||
|
|
@ -790,3 +714,176 @@ func (w *worker) fillTransactionsWithDelay(ctx context.Context, interrupt *int32
|
|||
attribute.Int("len of final remote txs", remoteEnvTCount),
|
||||
)
|
||||
}
|
||||
|
||||
// commitTransactionsWithDelay is commitTransactions() with extra params to induce artficial delays for tests such as commit-interrupt.
|
||||
// nolint:gocognit, unparam
|
||||
func (w *worker) commitTransactionsWithDelay(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *int32, interruptCtx context.Context) bool {
|
||||
gasLimit := env.header.GasLimit
|
||||
if env.gasPool == nil {
|
||||
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||
}
|
||||
|
||||
var coalescedLogs []*types.Log
|
||||
|
||||
initialGasLimit := env.gasPool.Gas()
|
||||
initialTxs := txs.GetTxs()
|
||||
|
||||
var breakCause string
|
||||
|
||||
defer func() {
|
||||
log.OnDebug(func(lg log.Logging) {
|
||||
lg("commitTransactions-stats",
|
||||
"initialTxsCount", initialTxs,
|
||||
"initialGasLimit", initialGasLimit,
|
||||
"resultTxsCount", txs.GetTxs(),
|
||||
"resultGapPool", env.gasPool.Gas(),
|
||||
"exitCause", breakCause)
|
||||
})
|
||||
}()
|
||||
|
||||
mainloop:
|
||||
for {
|
||||
if interruptCtx != nil {
|
||||
// case of interrupting by timeout
|
||||
select {
|
||||
case <-interruptCtx.Done():
|
||||
log.Warn("Interrupt")
|
||||
break mainloop
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// In the following three cases, we will interrupt the execution of the transaction.
|
||||
// (1) new head block event arrival, the interrupt signal is 1
|
||||
// (2) worker start or restart, the interrupt signal is 1
|
||||
// (3) worker recreate the sealing block with any newly arrived transactions, the interrupt signal is 2.
|
||||
// For the first two cases, the semi-finished work will be discarded.
|
||||
// For the third case, the semi-finished work will be submitted to the consensus engine.
|
||||
if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone {
|
||||
// Notify resubmit loop to increase resubmitting interval due to too frequent commits.
|
||||
if atomic.LoadInt32(interrupt) == commitInterruptResubmit {
|
||||
ratio := float64(gasLimit-env.gasPool.Gas()) / float64(gasLimit)
|
||||
if ratio < 0.1 {
|
||||
// nolint:goconst
|
||||
ratio = 0.1
|
||||
}
|
||||
w.resubmitAdjustCh <- &intervalAdjust{
|
||||
ratio: ratio,
|
||||
inc: true,
|
||||
}
|
||||
}
|
||||
// nolint:goconst
|
||||
breakCause = "interrupt"
|
||||
|
||||
return atomic.LoadInt32(interrupt) == commitInterruptNewHead
|
||||
}
|
||||
// If we don't have enough gas for any further transactions then we're done
|
||||
if env.gasPool.Gas() < params.TxGas {
|
||||
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
|
||||
// nolint:goconst
|
||||
breakCause = "Not enough gas for further transactions"
|
||||
|
||||
break
|
||||
}
|
||||
// Retrieve the next transaction and abort if all done
|
||||
tx := txs.Peek()
|
||||
if tx == nil {
|
||||
// nolint:goconst
|
||||
breakCause = "all transactions has been included"
|
||||
break
|
||||
}
|
||||
// Error may be ignored here. The error has already been checked
|
||||
// during transaction acceptance is the transaction pool.
|
||||
//
|
||||
// We use the eip155 signer regardless of the current hf.
|
||||
from, _ := types.Sender(env.signer, tx)
|
||||
// Check whether the tx is replay protected. If we're not in the EIP155 hf
|
||||
// phase, start ignoring the sender until we do.
|
||||
if tx.Protected() && !w.chainConfig.IsEIP155(env.header.Number) {
|
||||
log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.chainConfig.EIP155Block)
|
||||
|
||||
txs.Pop()
|
||||
|
||||
continue
|
||||
}
|
||||
// Start executing the transaction
|
||||
env.state.Prepare(tx.Hash(), env.tcount)
|
||||
|
||||
var start time.Time
|
||||
|
||||
log.OnDebug(func(log.Logging) {
|
||||
start = time.Now()
|
||||
})
|
||||
|
||||
logs, err := w.commitTransaction(env, tx, interruptCtx)
|
||||
|
||||
if interruptCtx != nil {
|
||||
if delay := interruptCtx.Value(vm.InterruptCtxDelayKey); delay != nil {
|
||||
// nolint : durationcheck
|
||||
time.Sleep(time.Duration(delay.(uint)) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case errors.Is(err, core.ErrGasLimitReached):
|
||||
// Pop the current out-of-gas transaction without shifting in the next from the account
|
||||
log.Trace("Gas limit exceeded for current block", "sender", from)
|
||||
txs.Pop()
|
||||
|
||||
case errors.Is(err, core.ErrNonceTooLow):
|
||||
// New head notification data race between the transaction pool and miner, shift
|
||||
log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce())
|
||||
txs.Shift()
|
||||
|
||||
case errors.Is(err, core.ErrNonceTooHigh):
|
||||
// Reorg notification data race between the transaction pool and miner, skip account =
|
||||
log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce())
|
||||
txs.Pop()
|
||||
|
||||
case errors.Is(err, nil):
|
||||
// Everything ok, collect the logs and shift in the next transaction from the same account
|
||||
coalescedLogs = append(coalescedLogs, logs...)
|
||||
env.tcount++
|
||||
|
||||
txs.Shift()
|
||||
|
||||
log.OnDebug(func(lg log.Logging) {
|
||||
lg("Committed new tx", "tx hash", tx.Hash(), "from", from, "to", tx.To(), "nonce", tx.Nonce(), "gas", tx.Gas(), "gasPrice", tx.GasPrice(), "value", tx.Value(), "time spent", time.Since(start))
|
||||
})
|
||||
|
||||
case errors.Is(err, core.ErrTxTypeNotSupported):
|
||||
// Pop the unsupported transaction without shifting in the next from the account
|
||||
log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type())
|
||||
txs.Pop()
|
||||
|
||||
default:
|
||||
// Strange error, discard the transaction and get the next in line (note, the
|
||||
// nonce-too-high clause will prevent us from executing in vain).
|
||||
log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err)
|
||||
txs.Shift()
|
||||
}
|
||||
}
|
||||
|
||||
if !w.isRunning() && len(coalescedLogs) > 0 {
|
||||
// We don't push the pendingLogsEvent while we are sealing. The reason is that
|
||||
// when we are sealing, the worker will regenerate a sealing block every 3 seconds.
|
||||
// In order to avoid pushing the repeated pendingLog, we disable the pending log pushing.
|
||||
// make a copy, the state caches the logs and these logs get "upgraded" from pending to mined
|
||||
// logs by filling in the block hash when the block was mined by the local miner. This can
|
||||
// cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed.
|
||||
cpy := make([]*types.Log, len(coalescedLogs))
|
||||
for i, l := range coalescedLogs {
|
||||
cpy[i] = new(types.Log)
|
||||
*cpy[i] = *l
|
||||
}
|
||||
|
||||
w.pendingLogsFeed.Send(cpy)
|
||||
}
|
||||
// Notify resubmit loop to decrease resubmitting interval if current interval is larger
|
||||
// than the user-specified one.
|
||||
if interrupt != nil {
|
||||
w.resubmitAdjustCh <- &intervalAdjust{inc: false}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
175
miner/worker.go
175
miner/worker.go
|
|
@ -31,6 +31,7 @@ import (
|
|||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
|
@ -45,6 +46,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/blockstm"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
|
|
@ -96,7 +98,7 @@ const (
|
|||
var (
|
||||
sealedBlocksCounter = metrics.NewRegisteredCounter("worker/sealedBlocks", nil)
|
||||
sealedEmptyBlocksCounter = metrics.NewRegisteredCounter("worker/sealedEmptyBlocks", nil)
|
||||
commitInterruptCounter = metrics.NewRegisteredCounter("worker/commitInterrupt", nil)
|
||||
txCommitInterruptCounter = metrics.NewRegisteredCounter("worker/txCommitInterrupt", nil)
|
||||
)
|
||||
|
||||
// environment is the worker's current environment and holds all
|
||||
|
|
@ -274,35 +276,38 @@ type worker struct {
|
|||
fullTaskHook func() // Method to call before pushing the full sealing task.
|
||||
resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval.
|
||||
|
||||
profileCount *int32 // Global count for profiling
|
||||
profileCount *int32 // Global count for profiling
|
||||
interruptCommitFlag bool // Interrupt commit ( Default true )
|
||||
interruptedTxCache *vm.TxCache
|
||||
}
|
||||
|
||||
//nolint:staticcheck
|
||||
func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(header *types.Header) bool, init bool) *worker {
|
||||
worker := &worker{
|
||||
config: config,
|
||||
chainConfig: chainConfig,
|
||||
engine: engine,
|
||||
eth: eth,
|
||||
mux: mux,
|
||||
chain: eth.BlockChain(),
|
||||
isLocalBlock: isLocalBlock,
|
||||
localUncles: make(map[common.Hash]*types.Block),
|
||||
remoteUncles: make(map[common.Hash]*types.Block),
|
||||
unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), sealingLogAtDepth),
|
||||
pendingTasks: make(map[common.Hash]*task),
|
||||
txsCh: make(chan core.NewTxsEvent, txChanSize),
|
||||
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
||||
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
|
||||
newWorkCh: make(chan *newWorkReq),
|
||||
getWorkCh: make(chan *getWorkReq),
|
||||
taskCh: make(chan *task),
|
||||
resultCh: make(chan *types.Block, resultQueueSize),
|
||||
exitCh: make(chan struct{}),
|
||||
startCh: make(chan struct{}, 1),
|
||||
resubmitIntervalCh: make(chan time.Duration),
|
||||
resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
|
||||
noempty: 1,
|
||||
config: config,
|
||||
chainConfig: chainConfig,
|
||||
engine: engine,
|
||||
eth: eth,
|
||||
mux: mux,
|
||||
chain: eth.BlockChain(),
|
||||
isLocalBlock: isLocalBlock,
|
||||
localUncles: make(map[common.Hash]*types.Block),
|
||||
remoteUncles: make(map[common.Hash]*types.Block),
|
||||
unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), sealingLogAtDepth),
|
||||
pendingTasks: make(map[common.Hash]*task),
|
||||
txsCh: make(chan core.NewTxsEvent, txChanSize),
|
||||
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
||||
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
|
||||
newWorkCh: make(chan *newWorkReq),
|
||||
getWorkCh: make(chan *getWorkReq),
|
||||
taskCh: make(chan *task),
|
||||
resultCh: make(chan *types.Block, resultQueueSize),
|
||||
exitCh: make(chan struct{}),
|
||||
startCh: make(chan struct{}, 1),
|
||||
resubmitIntervalCh: make(chan time.Duration),
|
||||
resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
|
||||
noempty: 1,
|
||||
interruptCommitFlag: config.CommitInterruptFlag,
|
||||
}
|
||||
worker.profileCount = new(int32)
|
||||
// Subscribe NewTxsEvent for tx pool
|
||||
|
|
@ -311,6 +316,19 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
|
|||
worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh)
|
||||
worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh)
|
||||
|
||||
interruptedTxCache, err := lru.New(vm.InterruptedTxCacheSize)
|
||||
if err != nil {
|
||||
log.Warn("Failed to create interrupted tx cache", "err", err)
|
||||
}
|
||||
|
||||
worker.interruptedTxCache = &vm.TxCache{
|
||||
Cache: interruptedTxCache,
|
||||
}
|
||||
|
||||
if !worker.interruptCommitFlag {
|
||||
worker.noempty = 0
|
||||
}
|
||||
|
||||
// Sanitize recommit interval if the user-specified one is too short.
|
||||
recommit := worker.config.Recommit
|
||||
if recommit < minRecommitInterval {
|
||||
|
|
@ -581,7 +599,9 @@ func (w *worker) mainLoop(ctx context.Context) {
|
|||
select {
|
||||
case req := <-w.newWorkCh:
|
||||
//nolint:contextcheck
|
||||
w.commitWork(req.ctx, req.interrupt, req.noempty, req.timestamp)
|
||||
if w.isRunning() {
|
||||
w.commitWork(req.ctx, req.interrupt, req.noempty, req.timestamp)
|
||||
}
|
||||
|
||||
case req := <-w.getWorkCh:
|
||||
//nolint:contextcheck
|
||||
|
|
@ -655,8 +675,22 @@ func (w *worker) mainLoop(ctx context.Context) {
|
|||
txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs, cmath.FromBig(w.current.header.BaseFee))
|
||||
tcount := w.current.tcount
|
||||
|
||||
interruptCh, stopFn := getInterruptTimer(ctx, w.current, w.chain.CurrentBlock())
|
||||
w.commitTransactions(w.current, txset, nil, interruptCh)
|
||||
// nolint : contextcheck
|
||||
var interruptCtx = context.Background()
|
||||
|
||||
stopFn := func() {}
|
||||
|
||||
defer func() {
|
||||
stopFn()
|
||||
}()
|
||||
|
||||
if w.interruptCommitFlag {
|
||||
interruptCtx, stopFn = getInterruptTimer(ctx, w.current, w.chain.CurrentBlock())
|
||||
// nolint : staticcheck
|
||||
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache)
|
||||
}
|
||||
|
||||
w.commitTransactions(w.current, txset, nil, interruptCtx)
|
||||
|
||||
// Only update the snapshot if any new transactions were added
|
||||
// to the pending block
|
||||
|
|
@ -932,10 +966,12 @@ func (w *worker) updateSnapshot(env *environment) {
|
|||
w.snapshotState = env.state.Copy()
|
||||
}
|
||||
|
||||
func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*types.Log, error) {
|
||||
func (w *worker) commitTransaction(env *environment, tx *types.Transaction, interruptCtx context.Context) ([]*types.Log, error) {
|
||||
snap := env.state.Snapshot()
|
||||
|
||||
receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *w.chain.GetVMConfig())
|
||||
// nolint : staticcheck
|
||||
interruptCtx = vm.SetCurrentTxOnContext(interruptCtx, tx.Hash())
|
||||
receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *w.chain.GetVMConfig(), interruptCtx)
|
||||
if err != nil {
|
||||
env.state.RevertToSnapshot(snap)
|
||||
return nil, err
|
||||
|
|
@ -947,7 +983,7 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*
|
|||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *int32, interruptCh chan struct{}) bool {
|
||||
func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *int32, interruptCtx context.Context) bool {
|
||||
gasLimit := env.header.GasLimit
|
||||
if env.gasPool == nil {
|
||||
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||
|
|
@ -1019,16 +1055,19 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP
|
|||
|
||||
mainloop:
|
||||
for {
|
||||
if EnableMVHashMap {
|
||||
env.state.AddEmptyMVHashMap()
|
||||
}
|
||||
if interruptCtx != nil {
|
||||
if EnableMVHashMap {
|
||||
env.state.AddEmptyMVHashMap()
|
||||
}
|
||||
|
||||
// case of interrupting by timeout
|
||||
select {
|
||||
case <-interruptCh:
|
||||
commitInterruptCounter.Inc(1)
|
||||
break mainloop
|
||||
default:
|
||||
// case of interrupting by timeout
|
||||
select {
|
||||
case <-interruptCtx.Done():
|
||||
txCommitInterruptCounter.Inc(1)
|
||||
log.Warn("Tx Level Interrupt")
|
||||
break mainloop
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// In the following three cases, we will interrupt the execution of the transaction.
|
||||
|
|
@ -1088,7 +1127,7 @@ mainloop:
|
|||
start = time.Now()
|
||||
})
|
||||
|
||||
logs, err := w.commitTransaction(env, tx)
|
||||
logs, err := w.commitTransaction(env, tx, interruptCtx)
|
||||
|
||||
switch {
|
||||
case errors.Is(err, core.ErrGasLimitReached):
|
||||
|
|
@ -1379,7 +1418,7 @@ func startProfiler(profile string, filepath string, number uint64) (func() error
|
|||
// be customized with the plugin in the future.
|
||||
//
|
||||
//nolint:gocognit
|
||||
func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *environment, interruptCh chan struct{}) {
|
||||
func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *environment, interruptCtx context.Context) {
|
||||
ctx, span := tracing.StartSpan(ctx, "fillTransactions")
|
||||
defer tracing.EndSpan(span)
|
||||
|
||||
|
|
@ -1503,7 +1542,7 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
})
|
||||
|
||||
tracing.Exec(ctx, "", "worker.LocalCommitTransactions", func(ctx context.Context, span trace.Span) {
|
||||
committed = w.commitTransactions(env, txs, interrupt, interruptCh)
|
||||
committed = w.commitTransactions(env, txs, interrupt, interruptCtx)
|
||||
})
|
||||
|
||||
if committed {
|
||||
|
|
@ -1526,7 +1565,7 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *en
|
|||
})
|
||||
|
||||
tracing.Exec(ctx, "", "worker.RemoteCommitTransactions", func(ctx context.Context, span trace.Span) {
|
||||
committed = w.commitTransactions(env, txs, interrupt, interruptCh)
|
||||
committed = w.commitTransactions(env, txs, interrupt, interruptCtx)
|
||||
})
|
||||
|
||||
if committed {
|
||||
|
|
@ -1551,10 +1590,22 @@ func (w *worker) generateWork(ctx context.Context, params *generateParams) (*typ
|
|||
}
|
||||
defer work.discard()
|
||||
|
||||
interruptCh, stopFn := getInterruptTimer(ctx, work, w.chain.CurrentBlock())
|
||||
defer stopFn()
|
||||
// nolint : contextcheck
|
||||
var interruptCtx = context.Background()
|
||||
|
||||
w.fillTransactions(ctx, nil, work, interruptCh)
|
||||
stopFn := func() {}
|
||||
|
||||
defer func() {
|
||||
stopFn()
|
||||
}()
|
||||
|
||||
if w.interruptCommitFlag {
|
||||
interruptCtx, stopFn = getInterruptTimer(ctx, work, w.chain.CurrentBlock())
|
||||
// nolint : staticcheck
|
||||
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache)
|
||||
}
|
||||
|
||||
w.fillTransactions(ctx, nil, work, interruptCtx)
|
||||
|
||||
return w.engine.FinalizeAndAssemble(ctx, w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts)
|
||||
}
|
||||
|
|
@ -1592,15 +1643,18 @@ func (w *worker) commitWork(ctx context.Context, interrupt *int32, noempty bool,
|
|||
return
|
||||
}
|
||||
|
||||
var interruptCh chan struct{}
|
||||
// nolint : contextcheck
|
||||
var interruptCtx = context.Background()
|
||||
|
||||
stopFn := func() {}
|
||||
defer func() {
|
||||
stopFn()
|
||||
}()
|
||||
|
||||
if !noempty {
|
||||
interruptCh, stopFn = getInterruptTimer(ctx, work, w.chain.CurrentBlock())
|
||||
if !noempty && w.interruptCommitFlag {
|
||||
interruptCtx, stopFn = getInterruptTimer(ctx, work, w.chain.CurrentBlock())
|
||||
// nolint : staticcheck
|
||||
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache)
|
||||
}
|
||||
|
||||
ctx, span := tracing.StartSpan(ctx, "commitWork")
|
||||
|
|
@ -1621,7 +1675,7 @@ func (w *worker) commitWork(ctx context.Context, interrupt *int32, noempty bool,
|
|||
}
|
||||
|
||||
// Fill pending transactions from the txpool
|
||||
w.fillTransactions(ctx, interrupt, work, interruptCh)
|
||||
w.fillTransactions(ctx, interrupt, work, interruptCtx)
|
||||
|
||||
err = w.commit(ctx, work.copy(), w.fullTaskHook, true, start)
|
||||
if err != nil {
|
||||
|
|
@ -1637,28 +1691,25 @@ func (w *worker) commitWork(ctx context.Context, interrupt *int32, noempty bool,
|
|||
w.current = work
|
||||
}
|
||||
|
||||
func getInterruptTimer(ctx context.Context, work *environment, current *types.Block) (chan struct{}, func()) {
|
||||
func getInterruptTimer(ctx context.Context, work *environment, current *types.Block) (context.Context, func()) {
|
||||
delay := time.Until(time.Unix(int64(work.header.Time), 0))
|
||||
|
||||
timeoutTimer := time.NewTimer(delay)
|
||||
stopFn := func() {
|
||||
timeoutTimer.Stop()
|
||||
}
|
||||
interruptCtx, cancel := context.WithTimeout(context.Background(), delay)
|
||||
|
||||
blockNumber := current.NumberU64() + 1
|
||||
interruptCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-timeoutTimer.C:
|
||||
log.Info("Commit Interrupt. Pre-committing the current block", "block", blockNumber)
|
||||
|
||||
close(interruptCh)
|
||||
case <-interruptCtx.Done():
|
||||
if interruptCtx.Err() != context.Canceled {
|
||||
log.Info("Commit Interrupt. Pre-committing the current block", "block", blockNumber)
|
||||
cancel()
|
||||
}
|
||||
case <-ctx.Done(): // nothing to do
|
||||
}
|
||||
}()
|
||||
|
||||
return interruptCh, stopFn
|
||||
return interruptCtx, cancel
|
||||
}
|
||||
|
||||
// commit runs any post-transaction state modifications, assembles the final block
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package miner
|
|||
import (
|
||||
"math/big"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -43,21 +42,18 @@ import (
|
|||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||
)
|
||||
|
||||
// nolint : paralleltest
|
||||
func TestGenerateBlockAndImportEthash(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testGenerateBlockAndImport(t, false, false)
|
||||
}
|
||||
|
||||
// nolint : paralleltest
|
||||
func TestGenerateBlockAndImportClique(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testGenerateBlockAndImport(t, true, false)
|
||||
}
|
||||
|
||||
// nolint : paralleltest
|
||||
func TestGenerateBlockAndImportBor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testGenerateBlockAndImport(t, false, true)
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +86,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) {
|
|||
|
||||
chainConfig.LondonBlock = big.NewInt(0)
|
||||
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, db, 0, 0, 0)
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, db, 0, 0, 0, 0)
|
||||
defer w.close()
|
||||
|
||||
// This test chain imports the mined blocks.
|
||||
|
|
@ -196,7 +192,7 @@ func TestEmptyWorkClique(t *testing.T) {
|
|||
func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
|
||||
defer engine.Close()
|
||||
|
||||
w, _, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0, 0, 0)
|
||||
w, _, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0, 0, 0, 0)
|
||||
defer w.close()
|
||||
|
||||
var (
|
||||
|
|
@ -250,7 +246,7 @@ func TestStreamUncleBlock(t *testing.T) {
|
|||
ethash := ethash.NewFaker()
|
||||
defer ethash.Close()
|
||||
|
||||
w, b, _ := NewTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1, 0, 0)
|
||||
w, b, _ := NewTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1, 0, 0, 0)
|
||||
defer w.close()
|
||||
|
||||
var taskCh = make(chan struct{})
|
||||
|
|
@ -312,7 +308,7 @@ func TestRegenerateMiningBlockClique(t *testing.T) {
|
|||
func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
|
||||
defer engine.Close()
|
||||
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0, 0, 0)
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0, 0, 0, 0)
|
||||
defer w.close()
|
||||
|
||||
var taskCh = make(chan struct{}, 3)
|
||||
|
|
@ -383,7 +379,7 @@ func TestAdjustIntervalClique(t *testing.T) {
|
|||
func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
|
||||
defer engine.Close()
|
||||
|
||||
w, _, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0, 0, 0)
|
||||
w, _, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0, 0, 0, 0)
|
||||
defer w.close()
|
||||
|
||||
w.skipSealHook = func(task *task) bool {
|
||||
|
|
@ -491,7 +487,7 @@ func TestGetSealingWorkPostMerge(t *testing.T) {
|
|||
func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, postMerge bool) {
|
||||
defer engine.Close()
|
||||
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0, 0, 0)
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0, 0, 0, 0)
|
||||
defer w.close()
|
||||
|
||||
w.setExtra([]byte{0x01, 0x02})
|
||||
|
|
@ -627,23 +623,41 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
|||
}
|
||||
}
|
||||
|
||||
// nolint : paralleltest
|
||||
// TestCommitInterruptExperimentBor tests the commit interrupt experiment for bor consensus by inducing an artificial delay at transaction level.
|
||||
func TestCommitInterruptExperimentBor(t *testing.T) {
|
||||
t.Parallel()
|
||||
// with 1 sec block time and 200 millisec tx delay we should get 5 txs per block
|
||||
testCommitInterruptExperimentBor(t, 200, 5)
|
||||
testCommitInterruptExperimentBor(t, 200, 5, 0)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// with 1 sec block time and 100 millisec tx delay we should get 10 txs per block
|
||||
testCommitInterruptExperimentBor(t, 100, 10)
|
||||
testCommitInterruptExperimentBor(t, 100, 10, 0)
|
||||
}
|
||||
|
||||
func testCommitInterruptExperimentBor(t *testing.T, delay uint, txCount int) {
|
||||
t.Helper()
|
||||
// nolint : paralleltest
|
||||
// TestCommitInterruptExperimentBorContract tests the commit interrupt experiment for bor consensus by inducing an artificial delay at OPCODE level.
|
||||
func TestCommitInterruptExperimentBorContract(t *testing.T) {
|
||||
// pre-calculated number of OPCODES = 123. 7*123=861 < 1000, 1 tx is possible but 2 tx per block will not be possible.
|
||||
testCommitInterruptExperimentBorContract(t, 0, 1, 7)
|
||||
time.Sleep(2 * time.Second)
|
||||
// pre-calculated number of OPCODES = 123. 2*123=246 < 1000, 4 tx is possible but 5 tx per block will not be possible. But 3 happen due to other overheads.
|
||||
testCommitInterruptExperimentBorContract(t, 0, 3, 2)
|
||||
time.Sleep(2 * time.Second)
|
||||
// pre-calculated number of OPCODES = 123. 3*123=369 < 1000, 2 tx is possible but 3 tx per block will not be possible.
|
||||
testCommitInterruptExperimentBorContract(t, 0, 2, 3)
|
||||
}
|
||||
|
||||
// nolint : thelper
|
||||
// testCommitInterruptExperimentBorContract is a helper function for testing the commit interrupt experiment for bor consensus.
|
||||
func testCommitInterruptExperimentBorContract(t *testing.T, delay uint, txCount int, opcodeDelay uint) {
|
||||
var (
|
||||
engine consensus.Engine
|
||||
chainConfig *params.ChainConfig
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
ctrl *gomock.Controller
|
||||
txInTxpool = 100
|
||||
txs = make([]*types.Transaction, 0, txInTxpool)
|
||||
)
|
||||
|
||||
chainConfig = params.BorUnittestChainConfig
|
||||
|
|
@ -651,38 +665,91 @@ func testCommitInterruptExperimentBor(t *testing.T, delay uint, txCount int) {
|
|||
log.Root().SetHandler(log.LvlFilterHandler(4, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
|
||||
engine, ctrl = getFakeBorFromConfig(t, chainConfig)
|
||||
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, db, 0, 1, delay, opcodeDelay)
|
||||
defer func() {
|
||||
w.close()
|
||||
engine.Close()
|
||||
db.Close()
|
||||
ctrl.Finish()
|
||||
}()
|
||||
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, db, 0, 1, delay)
|
||||
defer w.close()
|
||||
// nonce 0 tx
|
||||
tx, addr := b.newStorageCreateContractTx()
|
||||
if err := b.TxPool().AddRemote(tx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(1)
|
||||
time.Sleep(4 * time.Second)
|
||||
|
||||
go func() {
|
||||
wg.Done()
|
||||
// nonce starts from 1 because we already have one tx
|
||||
initNonce := uint64(1)
|
||||
|
||||
for {
|
||||
tx := b.newRandomTx(false)
|
||||
if err := b.TxPool().AddRemote(tx); err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
for i := 0; i < txInTxpool; i++ {
|
||||
tx := b.newStorageContractCallTx(addr, initNonce+uint64(i))
|
||||
txs = append(txs, tx)
|
||||
}
|
||||
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
if err := b.TxPool().AddRemotes(txs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Start mining!
|
||||
w.start()
|
||||
time.Sleep(5 * time.Second)
|
||||
w.stop()
|
||||
|
||||
assert.Equal(t, txCount, w.chain.CurrentBlock().Transactions().Len())
|
||||
currentBlockNumber := w.current.header.Number.Uint64()
|
||||
assert.Check(t, txCount >= w.chain.GetBlockByNumber(currentBlockNumber-1).Transactions().Len())
|
||||
assert.Check(t, 0 < w.chain.GetBlockByNumber(currentBlockNumber-1).Transactions().Len()+1)
|
||||
}
|
||||
|
||||
// nolint : thelper
|
||||
// testCommitInterruptExperimentBor is a helper function for testing the commit interrupt experiment for bor consensus.
|
||||
func testCommitInterruptExperimentBor(t *testing.T, delay uint, txCount int, opcodeDelay uint) {
|
||||
var (
|
||||
engine consensus.Engine
|
||||
chainConfig *params.ChainConfig
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
ctrl *gomock.Controller
|
||||
txInTxpool = 100
|
||||
txs = make([]*types.Transaction, 0, txInTxpool)
|
||||
)
|
||||
|
||||
chainConfig = params.BorUnittestChainConfig
|
||||
|
||||
log.Root().SetHandler(log.LvlFilterHandler(4, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
|
||||
engine, ctrl = getFakeBorFromConfig(t, chainConfig)
|
||||
|
||||
w, b, _ := NewTestWorker(t, chainConfig, engine, db, 0, 1, delay, opcodeDelay)
|
||||
defer func() {
|
||||
w.close()
|
||||
engine.Close()
|
||||
db.Close()
|
||||
ctrl.Finish()
|
||||
}()
|
||||
|
||||
// nonce starts from 0 because have no txs yet
|
||||
initNonce := uint64(0)
|
||||
|
||||
for i := 0; i < txInTxpool; i++ {
|
||||
tx := b.newRandomTxWithNonce(false, initNonce+uint64(i))
|
||||
txs = append(txs, tx)
|
||||
}
|
||||
|
||||
if err := b.TxPool().AddRemotes(txs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Start mining!
|
||||
w.start()
|
||||
time.Sleep(5 * time.Second)
|
||||
w.stop()
|
||||
|
||||
currentBlockNumber := w.current.header.Number.Uint64()
|
||||
assert.Check(t, txCount >= w.chain.GetBlockByNumber(currentBlockNumber-1).Transactions().Len())
|
||||
assert.Check(t, 0 < w.chain.GetBlockByNumber(currentBlockNumber-1).Transactions().Len())
|
||||
}
|
||||
|
||||
func BenchmarkBorMining(b *testing.B) {
|
||||
|
|
@ -716,7 +783,7 @@ func BenchmarkBorMining(b *testing.B) {
|
|||
|
||||
chainConfig.LondonBlock = big.NewInt(0)
|
||||
|
||||
w, back, _ := NewTestWorker(b, chainConfig, engine, db, 0, 0, 0)
|
||||
w, back, _ := NewTestWorker(b, chainConfig, engine, db, 0, 0, 0, 0)
|
||||
defer w.close()
|
||||
|
||||
// This test chain imports the mined blocks.
|
||||
|
|
@ -822,7 +889,7 @@ func BenchmarkBorMiningBlockSTMMetadata(b *testing.B) {
|
|||
|
||||
chainConfig.LondonBlock = big.NewInt(0)
|
||||
|
||||
w, back, _ := NewTestWorker(b, chainConfig, engine, db, 0, 0, 0)
|
||||
w, back, _ := NewTestWorker(b, chainConfig, engine, db, 0, 0, 0, 0)
|
||||
defer w.close()
|
||||
|
||||
// This test chain imports the mined blocks.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor
|
||||
Version: 0.3.8-beta
|
||||
Version: 0.3.9-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor
|
||||
Version: 0.3.8-beta
|
||||
Version: 0.3.9-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor-profile
|
||||
Version: 0.3.8-beta
|
||||
Version: 0.3.9-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor-profile
|
||||
Version: 0.3.8-beta
|
||||
Version: 0.3.9-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor-profile
|
||||
Version: 0.3.8-beta
|
||||
Version: 0.3.9-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Source: bor-profile
|
||||
Version: 0.3.8-beta
|
||||
Version: 0.3.9-beta
|
||||
Section: develop
|
||||
Priority: standard
|
||||
Maintainer: Polygon <release-team@polygon.technology>
|
||||
|
|
|
|||
16
packaging/templates/systemd/bor_bootnode.service
Normal file
16
packaging/templates/systemd/bor_bootnode.service
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[Unit]
|
||||
Description=bor
|
||||
StartLimitIntervalSec=500
|
||||
StartLimitBurst=5
|
||||
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
ExecStart=/usr/bin/bor bootnode -nodekey /var/lib/bor/config/nodekey -addr ":30303" -verbosity 5
|
||||
Type=simple
|
||||
KillSignal=SIGINT
|
||||
User=bor
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -21,13 +21,14 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
GitCommit = ""
|
||||
VersionMajor = 0 // Major version component of the current release
|
||||
VersionMinor = 3 // Minor version component of the current release
|
||||
VersionPatch = 8 // Patch version component of the current release
|
||||
VersionPatch = 9 // Patch version component of the current release
|
||||
VersionMeta = "beta" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
var GitCommit string
|
||||
|
||||
// Version holds the textual version string.
|
||||
var Version = func() string {
|
||||
return fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch)
|
||||
|
|
@ -42,13 +43,13 @@ var VersionWithMeta = func() string {
|
|||
return v
|
||||
}()
|
||||
|
||||
// VersionWithCommitDetails holds the textual version string including the metadata and Git Details.
|
||||
// VersionWithMetaCommitDetails holds the textual version string including the metadata and Git Details.
|
||||
var VersionWithMetaCommitDetails = func() string {
|
||||
v := Version
|
||||
if VersionMeta != "" {
|
||||
v += "-" + VersionMeta
|
||||
}
|
||||
v_git := fmt.Sprintf("Version : %s\nGitCommit : %s\n", v, GitCommit)
|
||||
v_git := fmt.Sprintf("Version: %s\nGitCommit: %s", v, GitCommit)
|
||||
return v_git
|
||||
}()
|
||||
|
||||
|
|
|
|||
|
|
@ -577,90 +577,112 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
|||
require.Equal(t, uint64(6), lastStateID.Uint64())
|
||||
}
|
||||
|
||||
// Abs returns the absolute value of x.
|
||||
func Abs(x int) int {
|
||||
if x < 0 {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func TestOutOfTurnSigning(t *testing.T) {
|
||||
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
||||
chain := init.ethereum.BlockChain()
|
||||
engine := init.ethereum.Engine()
|
||||
_bor := engine.(*bor.Bor)
|
||||
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
fdlimit.Raise(2048)
|
||||
|
||||
defer _bor.Close()
|
||||
// Generate a batch of accounts to seal and fund with
|
||||
faucets := make([]*ecdsa.PrivateKey, 128)
|
||||
for i := 0; i < len(faucets); i++ {
|
||||
faucets[i], _ = crypto.GenerateKey()
|
||||
}
|
||||
|
||||
_, heimdallSpan := loadSpanFromFile(t)
|
||||
proposer := valset.NewValidator(addr, 10)
|
||||
heimdallSpan.ValidatorSet.Validators = append(heimdallSpan.ValidatorSet.Validators, proposer)
|
||||
// Create an Ethash network based off of the Ropsten config
|
||||
// Generate a batch of accounts to seal and fund with
|
||||
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
||||
|
||||
// add the block producer
|
||||
h, ctrl := getMockedHeimdallClient(t, heimdallSpan)
|
||||
defer ctrl.Finish()
|
||||
var (
|
||||
stacks []*node.Node
|
||||
nodes []*eth.Ethereum
|
||||
enodes []*enode.Node
|
||||
)
|
||||
for i := 0; i < 2; i++ {
|
||||
// Start the node and wait until it's up
|
||||
stack, ethBackend, err := InitMiner(genesis, keys[i], true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer stack.Close()
|
||||
|
||||
h.EXPECT().Close().AnyTimes()
|
||||
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
// Connect the node to all the previous ones
|
||||
for _, n := range enodes {
|
||||
stack.Server().AddPeer(n)
|
||||
}
|
||||
// Start tracking the node and its enode
|
||||
stacks = append(stacks, stack)
|
||||
nodes = append(nodes, ethBackend)
|
||||
enodes = append(enodes, stack.Server().Self())
|
||||
}
|
||||
|
||||
spanner := getMockedSpanner(t, heimdallSpan.ValidatorSet.Validators)
|
||||
_bor.SetSpanner(spanner)
|
||||
_bor.SetHeimdallClient(h)
|
||||
|
||||
db := init.ethereum.ChainDb()
|
||||
block := init.genesis.ToBlock(db)
|
||||
|
||||
setDifficulty := func(header *types.Header) {
|
||||
if IsSprintStart(header.Number.Uint64()) {
|
||||
header.Difficulty = big.NewInt(int64(len(heimdallSpan.ValidatorSet.Validators)))
|
||||
// Iterate over all the nodes and start mining
|
||||
time.Sleep(3 * time.Second)
|
||||
for _, node := range nodes {
|
||||
if err := node.StartMining(1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := uint64(1); i < spanSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators, setDifficulty)
|
||||
insertNewBlock(t, chain, block)
|
||||
for {
|
||||
|
||||
// for block 1 to 8, the primary validator is node0
|
||||
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
||||
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
||||
|
||||
// we remove peer connection between node0 and node1
|
||||
if blockHeaderVal0.Number.Uint64() == 1 {
|
||||
stacks[0].Server().RemovePeer(enodes[1])
|
||||
}
|
||||
|
||||
if blockHeaderVal1.Number.Uint64() == 9 {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// insert spanSize-th block
|
||||
// This account is one the out-of-turn validators for 1st (0-indexed) span
|
||||
signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
|
||||
signerKey, _ := hex.DecodeString(signer)
|
||||
newKey, _ := crypto.HexToECDSA(signer)
|
||||
newAddr := crypto.PubkeyToAddress(newKey.PublicKey)
|
||||
expectedSuccessionNumber := 2
|
||||
// function to get timestamp difference between two nodes of the same blockNumber
|
||||
timeDiff := func(blockNum int) int {
|
||||
blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(uint64(blockNum))
|
||||
blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(uint64(blockNum))
|
||||
|
||||
parentTime := block.Time()
|
||||
|
||||
setParentTime := func(header *types.Header) {
|
||||
header.Time = parentTime + 1
|
||||
return Abs(int(blockHeaderVal0.Time - blockHeaderVal1.Time))
|
||||
}
|
||||
|
||||
const turn = 1
|
||||
// check block 10 miner ; expected author is node1 signer
|
||||
blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(3)
|
||||
blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(3)
|
||||
|
||||
setDifficulty = func(header *types.Header) {
|
||||
header.Difficulty = big.NewInt(int64(len(heimdallSpan.ValidatorSet.Validators)) - turn)
|
||||
}
|
||||
// check both nodes have the same block 10
|
||||
assert.Equal(t, blockHeaderVal0.Difficulty, common.Big2)
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators, setParentTime, setDifficulty)
|
||||
_, err := chain.InsertChain([]*types.Block{block})
|
||||
require.Equal(t,
|
||||
bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber},
|
||||
*err.(*bor.BlockTooSoonError))
|
||||
// check node0 has block mined by node1
|
||||
assert.Equal(t, blockHeaderVal1.Difficulty, common.Big1)
|
||||
|
||||
expectedDifficulty := uint64(len(heimdallSpan.ValidatorSet.Validators) - expectedSuccessionNumber - turn) // len(validators) - succession
|
||||
header := block.Header()
|
||||
// node seperated at block 1, so at block 3, node0 should be at 3 seconds, and node1 should be at 5( 1 + 2*2 ) seconds
|
||||
assert.Equal(t, timeDiff(3), 2)
|
||||
|
||||
diff := bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor)
|
||||
header.Time += diff
|
||||
// check block 10 miner ; expected author is node1 signer
|
||||
blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(7)
|
||||
blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(7)
|
||||
|
||||
sign(t, header, signerKey, init.genesis.Config.Bor)
|
||||
// check both nodes have the same block 10
|
||||
assert.Equal(t, blockHeaderVal0.Difficulty, common.Big2)
|
||||
|
||||
block = types.NewBlockWithHeader(header)
|
||||
// check node0 has block mined by node1
|
||||
assert.Equal(t, blockHeaderVal1.Difficulty, common.Big1)
|
||||
|
||||
_, err = chain.InsertChain([]*types.Block{block})
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t,
|
||||
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: newAddr.Bytes()},
|
||||
*err.(*bor.WrongDifficultyError))
|
||||
|
||||
header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
|
||||
sign(t, header, signerKey, init.genesis.Config.Bor)
|
||||
block = types.NewBlockWithHeader(header)
|
||||
|
||||
_, err = chain.InsertChain([]*types.Block{block})
|
||||
require.Nil(t, err)
|
||||
// node seperated at block 1, so at block 7, node0 should be at 7 seconds, and node1 should be at 13( 1 + 2*6 ) seconds
|
||||
assert.Equal(t, timeDiff(7), 6)
|
||||
}
|
||||
|
||||
func TestSignerNotFound(t *testing.T) {
|
||||
|
|
@ -1099,11 +1121,18 @@ func TestJaipurFork(t *testing.T) {
|
|||
|
||||
res, _ := loadSpanFromFile(t)
|
||||
|
||||
spanner := getMockedSpanner(t, res.Result.ValidatorSet.Validators)
|
||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||
|
||||
spanner := getMockedSpanner(t, currentValidators)
|
||||
_bor.SetSpanner(spanner)
|
||||
|
||||
for i := uint64(1); i < sprintSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
|
||||
if IsSpanEnd(i) {
|
||||
currentValidators = res.Result.ValidatorSet.Validators
|
||||
}
|
||||
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||
|
||||
insertNewBlock(t, chain, block)
|
||||
|
||||
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock.Uint64()-1 {
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ func (b *blockGen) addTxWithChain(bc *core.BlockChain, statedb *state.StateDB, t
|
|||
|
||||
statedb.Prepare(tx.Hash(), len(b.txs))
|
||||
|
||||
receipt, err := core.ApplyTransaction(bc.Config(), bc, &b.header.Coinbase, b.gasPool, statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
|
||||
receipt, err := core.ApplyTransaction(bc.Config(), bc, &b.header.Coinbase, b.gasPool, statedb, b.header, tx, &b.header.GasUsed, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
|||
for n := 0; n < b.N; n++ {
|
||||
// Execute the message.
|
||||
snapshot := statedb.Snapshot()
|
||||
_, _, err = evm.Call(sender, *msg.To(), msg.Data(), msg.Gas(), msg.Value())
|
||||
_, _, err = evm.Call(sender, *msg.To(), msg.Data(), msg.Gas(), msg.Value(), nil)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -232,7 +232,8 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
|||
snapshot := statedb.Snapshot()
|
||||
gaspool := new(core.GasPool)
|
||||
gaspool.AddGas(block.GasLimit())
|
||||
if _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
|
||||
|
||||
if _, err := core.ApplyMessage(evm, msg, gaspool, nil); err != nil {
|
||||
statedb.RevertToSnapshot(snapshot)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue