Add support for PulseChain

Thanks @bretep for the original integration.
This commit is contained in:
Shane Bammel 2023-02-24 20:54:12 -06:00
parent aa3a804757
commit 75db06fa1d
43 changed files with 542 additions and 129 deletions

View File

@ -42,17 +42,6 @@ FROM docker.io/library/alpine:3.17
RUN apk add --no-cache ca-certificates libstdc++ tzdata RUN apk add --no-cache ca-certificates libstdc++ tzdata
RUN apk add --no-cache curl jq bind-tools RUN apk add --no-cache curl jq bind-tools
# Setup user and group
#
# from the perspective of the container, uid=1000, gid=1000 is a sensible choice
# (mimicking Ubuntu Server), but if caller creates a .env (example in repo root),
# these defaults will get overridden when make calls docker-compose
ARG UID=1000
ARG GID=1000
RUN adduser -D -u $UID -g $GID erigon
USER erigon
RUN mkdir -p ~/.local/share/erigon
# copy compiled artifacts from builder # copy compiled artifacts from builder
## first do the mdbx ones - since these wont change as often ## first do the mdbx ones - since these wont change as often
COPY --from=tools-builder /app/build/bin/mdbx_chk /usr/local/bin/mdbx_chk COPY --from=tools-builder /app/build/bin/mdbx_chk /usr/local/bin/mdbx_chk
@ -98,13 +87,13 @@ ARG BUILD_DATE
ARG VCS_REF ARG VCS_REF
ARG VERSION ARG VERSION
LABEL org.label-schema.build-date=$BUILD_DATE \ LABEL org.label-schema.build-date=$BUILD_DATE \
org.label-schema.description="Erigon Ethereum Client" \ org.label-schema.description="Erigon Ethereum Client with PulseChain" \
org.label-schema.name="Erigon" \ org.label-schema.name="Erigon PulseChain" \
org.label-schema.schema-version="1.0" \ org.label-schema.schema-version="1.0" \
org.label-schema.url="https://torquem.ch" \ org.label-schema.url="https://gitlab.com/pulsechaincom/erigon-pulse" \
org.label-schema.vcs-ref=$VCS_REF \ org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vcs-url="https://github.com/ledgerwatch/erigon.git" \ org.label-schema.vcs-url="https://gitlab.com/pulsechaincom/erigon-pulse.git" \
org.label-schema.vendor="Torquem" \ org.label-schema.vendor="PulseChain" \
org.label-schema.version=$VERSION org.label-schema.version=$VERSION
ENTRYPOINT ["erigon"] ENTRYPOINT ["erigon"]

View File

@ -79,6 +79,7 @@ docker: validate_docker_build_args git-submodules
--build-arg VERSION=${GIT_TAG} \ --build-arg VERSION=${GIT_TAG} \
--build-arg UID=${DOCKER_UID} \ --build-arg UID=${DOCKER_UID} \
--build-arg GID=${DOCKER_GID} \ --build-arg GID=${DOCKER_GID} \
--build-arg DEPLOY_TOKEN=${DEPLOY_TOKEN} \
${DOCKER_FLAGS} \ ${DOCKER_FLAGS} \
. .

View File

@ -35,6 +35,7 @@ var (
maxPendPeers int maxPendPeers int
healthCheck bool healthCheck bool
metrics bool metrics bool
chainName string
) )
func init() { func init() {
@ -55,6 +56,7 @@ func init() {
rootCmd.Flags().IntVar(&maxPendPeers, utils.MaxPendingPeersFlag.Name, utils.MaxPendingPeersFlag.Value, utils.MaxPendingPeersFlag.Usage) rootCmd.Flags().IntVar(&maxPendPeers, utils.MaxPendingPeersFlag.Name, utils.MaxPendingPeersFlag.Value, utils.MaxPendingPeersFlag.Usage)
rootCmd.Flags().BoolVar(&healthCheck, utils.HealthCheckFlag.Name, false, utils.HealthCheckFlag.Usage) rootCmd.Flags().BoolVar(&healthCheck, utils.HealthCheckFlag.Name, false, utils.HealthCheckFlag.Usage)
rootCmd.Flags().BoolVar(&metrics, utils.MetricsEnabledFlag.Name, false, utils.MetricsEnabledFlag.Usage) rootCmd.Flags().BoolVar(&metrics, utils.MetricsEnabledFlag.Name, false, utils.MetricsEnabledFlag.Usage)
rootCmd.Flags().StringVar(&chainName, utils.ChainFlag.Name, utils.ChainFlag.Value, utils.ChainFlag.Usage)
if err := rootCmd.MarkFlagDirname(utils.DataDirFlag.Name); err != nil { if err := rootCmd.MarkFlagDirname(utils.DataDirFlag.Name); err != nil {
panic(err) panic(err)
@ -88,6 +90,7 @@ var rootCmd = &cobra.Command{
protocol, protocol,
allowedPorts, allowedPorts,
metrics, metrics,
chainName,
) )
if err != nil { if err != nil {
return err return err

View File

@ -97,7 +97,7 @@ var (
} }
ChainFlag = cli.StringFlag{ ChainFlag = cli.StringFlag{
Name: "chain", Name: "chain",
Usage: "name of the network to join", Usage: "Name of the network to join",
Value: networkname.MainnetChainName, Value: networkname.MainnetChainName,
} }
IdentityFlag = cli.StringFlag{ IdentityFlag = cli.StringFlag{
@ -1062,6 +1062,7 @@ func NewP2PConfig(
protocol uint, protocol uint,
allowedPorts []uint, allowedPorts []uint,
metricsEnabled bool, metricsEnabled bool,
chainName string,
) (*p2p.Config, error) { ) (*p2p.Config, error) {
var enodeDBPath string var enodeDBPath string
switch protocol { switch protocol {
@ -1092,6 +1093,7 @@ func NewP2PConfig(
AllowedPorts: allowedPorts, AllowedPorts: allowedPorts,
TmpDir: dirs.Tmp, TmpDir: dirs.Tmp,
MetricsEnabled: metricsEnabled, MetricsEnabled: metricsEnabled,
ChainName: chainName,
} }
if netRestrict != "" { if netRestrict != "" {
cfg.NetRestrict = new(netutil.Netlist) cfg.NetRestrict = new(netutil.Netlist)
@ -1771,7 +1773,7 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis libcommon.Hash) {
return // already set through flags/config return // already set through flags/config
} }
protocol := "all" protocol := "all"
if url := params.KnownDNSNetwork(genesis, protocol); url != "" { if url := params.KnownDNSNetwork(genesis, cfg.NetworkID, protocol); url != "" {
cfg.EthDiscoveryURLs = []string{url} cfg.EthDiscoveryURLs = []string{url}
} }
} }

View File

@ -100,6 +100,10 @@ func DataDirForNetwork(datadir string, network string) string {
return networkDataDirCheckingLegacy(datadir, "gnosis") return networkDataDirCheckingLegacy(datadir, "gnosis")
case networkname.ChiadoChainName: case networkname.ChiadoChainName:
return networkDataDirCheckingLegacy(datadir, "chiado") return networkDataDirCheckingLegacy(datadir, "chiado")
case networkname.PulsechainChainName:
return networkDataDirCheckingLegacy(datadir, "pulsechain")
case networkname.PulsechainTestnetChainName:
return networkDataDirCheckingLegacy(datadir, "pulsechain-testnet")
default: default:
return datadir return datadir

View File

@ -39,6 +39,7 @@ import (
"github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/pulse"
"github.com/ledgerwatch/erigon/rlp" "github.com/ledgerwatch/erigon/rlp"
) )
@ -294,6 +295,8 @@ func (ethash *Ethash) CalcDifficulty(chain consensus.ChainHeaderReader, time, pa
func CalcDifficulty(config *chain.Config, time, parentTime uint64, parentDifficulty *big.Int, parentNumber uint64, parentUncleHash libcommon.Hash) *big.Int { func CalcDifficulty(config *chain.Config, time, parentTime uint64, parentDifficulty *big.Int, parentNumber uint64, parentUncleHash libcommon.Hash) *big.Int {
next := parentNumber + 1 next := parentNumber + 1
switch { switch {
case config.IsPrimordialPulseBlock(next):
return chain.PulseChainTTDOffset
case config.IsGrayGlacier(next): case config.IsGrayGlacier(next):
return calcDifficultyEip5133(time, parentTime, parentDifficulty, parentNumber, parentUncleHash) return calcDifficultyEip5133(time, parentTime, parentDifficulty, parentNumber, parentUncleHash)
case config.IsArrowGlacier(next): case config.IsArrowGlacier(next):
@ -562,6 +565,11 @@ func (ethash *Ethash) Finalize(config *chain.Config, header *types.Header, state
txs types.Transactions, uncles []*types.Header, r types.Receipts, withdrawals []*types.Withdrawal, txs types.Transactions, uncles []*types.Header, r types.Receipts, withdrawals []*types.Withdrawal,
chain consensus.ChainReader, syscall consensus.SystemCall, logger log.Logger, chain consensus.ChainReader, syscall consensus.SystemCall, logger log.Logger,
) (types.Transactions, types.Receipts, error) { ) (types.Transactions, types.Receipts, error) {
// Apply fork changes on PrimordialPulse block
if cfg := chain.Config(); cfg.IsPrimordialPulseBlock(header.Number.Uint64()) {
pulse.PrimordialPulseFork(state, cfg.PulseChain)
}
// Accumulate any block and uncle rewards and commit the final state root // Accumulate any block and uncle rewards and commit the final state root
accumulateRewards(config, state, header, uncles) accumulateRewards(config, state, header, uncles)
return txs, r, nil return txs, r, nil

View File

@ -82,8 +82,8 @@ func (s *Merge) VerifyHeader(chain consensus.ChainHeaderReader, header *types.He
if err != nil { if err != nil {
return err return err
} }
if !reached { if !reached && (chain.Config().PulseChain == nil || !misc.IsPoSHeader(header)) {
// Not verifying seals if the TTD is passed // Delegate non-PoS block to eth1 verification
return s.eth1Engine.VerifyHeader(chain, header, !chain.Config().TerminalTotalDifficultyPassed) return s.eth1Engine.VerifyHeader(chain, header, !chain.Config().TerminalTotalDifficultyPassed)
} }
// Short circuit if the parent is not known // Short circuit if the parent is not known

View File

@ -121,12 +121,18 @@ func WriteGenesisBlock(tx kv.RwTx, genesis *types.Genesis, overrideCancunTime *b
return genesis.Config, block, nil return genesis.Config, block, nil
} }
// Assume mainnet chainId first
chainId := params.MainnetChainConfig.ChainID.Uint64()
// Check whether the genesis block is already written. // Check whether the genesis block is already written.
if genesis != nil { if genesis != nil {
block, _, err1 := GenesisToBlock(genesis, tmpDir, logger) block, _, err1 := GenesisToBlock(genesis, tmpDir, logger)
if err1 != nil { if err1 != nil {
return genesis.Config, nil, err1 return genesis.Config, nil, err1
} }
// Use the incoming chainID for building chain config.
// Allows for mainnet genesis w/ pulsechain config.
chainId = genesis.Config.ChainID.Uint64()
hash := block.Hash() hash := block.Hash()
if hash != storedHash { if hash != storedHash {
return genesis.Config, block, &types.GenesisMismatchError{Stored: storedHash, New: hash} return genesis.Config, block, &types.GenesisMismatchError{Stored: storedHash, New: hash}
@ -140,13 +146,18 @@ func WriteGenesisBlock(tx kv.RwTx, genesis *types.Genesis, overrideCancunTime *b
return genesis.Config, nil, err return genesis.Config, nil, err
} }
} }
storedCfg, storedErr := rawdb.ReadChainConfig(tx, storedHash)
if storedErr == nil && storedCfg != nil {
// Use the existing chainID for building chain config.
// Allows for mainnet genesis w/ pulsechain config.
chainId = storedCfg.ChainID.Uint64()
}
// Get the existing chain configuration. // Get the existing chain configuration.
newCfg := genesis.ConfigOrDefault(storedHash) newCfg := genesis.ConfigOrDefault(storedHash, chainId)
applyOverrides(newCfg) applyOverrides(newCfg)
if err := newCfg.CheckConfigForkOrder(); err != nil { if err := newCfg.CheckConfigForkOrder(); err != nil {
return newCfg, nil, err return newCfg, nil, err
} }
storedCfg, storedErr := rawdb.ReadChainConfig(tx, storedHash)
if storedErr != nil && newCfg.Bor == nil { if storedErr != nil && newCfg.Bor == nil {
return newCfg, nil, storedErr return newCfg, nil, storedErr
} }
@ -457,6 +468,28 @@ func ChiadoGenesisBlock() *types.Genesis {
} }
} }
func PulsechainGenesisBlock() *types.Genesis {
return &types.Genesis{
Config: params.PulsechainChainConfig,
Nonce: 66,
ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"),
GasLimit: 5000,
Difficulty: big.NewInt(17179869184),
Alloc: readPrealloc("allocs/mainnet.json"),
}
}
func PulsechainTestnetGenesisBlock() *types.Genesis {
return &types.Genesis{
Config: params.PulsechainTestnetChainConfig,
Nonce: 66,
ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"),
GasLimit: 5000,
Difficulty: big.NewInt(17179869184),
Alloc: readPrealloc("allocs/mainnet.json"),
}
}
// Pre-calculated version of: // Pre-calculated version of:
// //
// DevnetSignPrivateKey = crypto.HexToECDSA(sha256.Sum256([]byte("erigon devnet key"))) // DevnetSignPrivateKey = crypto.HexToECDSA(sha256.Sum256([]byte("erigon devnet key")))
@ -675,6 +708,10 @@ func GenesisBlockByChainName(chain string) *types.Genesis {
return GnosisGenesisBlock() return GnosisGenesisBlock()
case networkname.ChiadoChainName: case networkname.ChiadoChainName:
return ChiadoGenesisBlock() return ChiadoGenesisBlock()
case networkname.PulsechainChainName:
return PulsechainGenesisBlock()
case networkname.PulsechainTestnetChainName:
return PulsechainTestnetGenesisBlock()
default: default:
return nil return nil
} }

View File

@ -38,6 +38,8 @@ import (
var analysisBlocks = map[string][]uint64{ var analysisBlocks = map[string][]uint64{
networkname.MainnetChainName: {5_800_596, 6_426_298, 6_426_432, 11_079_912, 13_119_520, 15_081_051}, networkname.MainnetChainName: {5_800_596, 6_426_298, 6_426_432, 11_079_912, 13_119_520, 15_081_051},
networkname.BorMainnetChainName: {29_447_463}, networkname.BorMainnetChainName: {29_447_463},
networkname.PulsechainChainName: {5_800_596, 6_426_298, 6_426_432, 11_079_912, 13_119_520, 15_081_051},
networkname.PulsechainTestnetChainName: {5_800_596, 6_426_298, 6_426_432, 11_079_912, 13_119_520, 15_081_051},
} }
func SkipAnalysis(config *chain.Config, blockNumber uint64) bool { func SkipAnalysis(config *chain.Config, blockNumber uint64) bool {

View File

@ -25,6 +25,7 @@ import (
"math/big" "math/big"
"github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/chain"
"github.com/ledgerwatch/erigon-lib/chain/networkname"
"github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/hexutility" "github.com/ledgerwatch/erigon-lib/common/hexutility"
@ -165,12 +166,23 @@ func (e *GenesisMismatchError) Error() string {
} }
return fmt.Sprintf("database contains incompatible genesis (try with --chain=%s)", config.ChainName) return fmt.Sprintf("database contains incompatible genesis (try with --chain=%s)", config.ChainName)
} }
func (g *Genesis) ConfigOrDefault(genesisHash common.Hash) *chain.Config { func (g *Genesis) ConfigOrDefault(genesisHash common.Hash, chainId uint64) *chain.Config {
if g != nil { if g != nil {
return g.Config return g.Config
} }
config := params.ChainConfigByGenesisHash(genesisHash) var config *chain.Config
pulseChainConfig := params.ChainConfigByChainName(networkname.PulsechainChainName)
pulseChainTestnetConfig := params.ChainConfigByChainName(networkname.PulsechainTestnetChainName)
switch chainId {
case pulseChainConfig.ChainID.Uint64():
config = pulseChainConfig
case pulseChainTestnetConfig.ChainID.Uint64():
config = pulseChainTestnetConfig
default:
config = params.ChainConfigByGenesisHash(genesisHash)
}
if config != nil { if config != nil {
return config return config
} else { } else {

View File

@ -42,6 +42,12 @@ func MakeSigner(config *chain.Config, blockNumber uint64, blockTime uint64) *Sig
if overflow { if overflow {
panic(fmt.Errorf("chainID higher than 2^256-1")) panic(fmt.Errorf("chainID higher than 2^256-1"))
} }
if config.PrimordialPulseAhead(blockNumber) {
// ethereum mainnet chainID is 1
// required to validate transactions on mainnet
chainId.SetOne()
}
} }
signer.unprotected = true signer.unprotected = true
switch { switch {

View File

@ -17,6 +17,7 @@
package vm package vm
import ( import (
"math/big"
"sync/atomic" "sync/atomic"
"github.com/holiman/uint256" "github.com/holiman/uint256"
@ -97,13 +98,24 @@ type EVM struct {
// NewEVM returns a new EVM. The returned EVM is not thread safe and should // NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*. // only ever be used *once*.
func NewEVM(blockCtx evmtypes.BlockContext, txCtx evmtypes.TxContext, state evmtypes.IntraBlockState, chainConfig *chain.Config, vmConfig Config) *EVM { func NewEVM(blockCtx evmtypes.BlockContext, txCtx evmtypes.TxContext, state evmtypes.IntraBlockState, chainConfig *chain.Config, vmConfig Config) *EVM {
flexChainConfig := chainConfig
if flexChainConfig.PrimordialPulseAhead(blockCtx.BlockNumber) {
// create a shallow of chainConfig struct and set to ethereum mainnet
chainCfgCpy := *chainConfig
chainCfgCpy.ChainID = big.NewInt(1)
// use the new chainCfgCpy
flexChainConfig = &chainCfgCpy
}
evm := &EVM{ evm := &EVM{
Context: blockCtx, Context: blockCtx,
TxContext: txCtx, TxContext: txCtx,
intraBlockState: state, intraBlockState: state,
config: vmConfig, config: vmConfig,
chainConfig: chainConfig, chainConfig: flexChainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Time), chainRules: flexChainConfig.Rules(blockCtx.BlockNumber, blockCtx.Time),
} }
evm.interpreter = NewEVMInterpreter(evm, vmConfig) evm.interpreter = NewEVMInterpreter(evm, vmConfig)

View File

@ -68,6 +68,9 @@ type Config struct {
CancunTime *big.Int `json:"cancunTime,omitempty"` CancunTime *big.Int `json:"cancunTime,omitempty"`
PragueTime *big.Int `json:"pragueTime,omitempty"` PragueTime *big.Int `json:"pragueTime,omitempty"`
// PulseChain fork blocks
PrimordialPulseBlock *big.Int `json:"primordialPulseBlock,omitempty"` // PrimordialPulseBlock switch block (nil = no fork, 0 = already activated)
// Optional EIP-4844 parameters // Optional EIP-4844 parameters
MinBlobGasPrice *uint64 `json:"minBlobGasPrice,omitempty"` MinBlobGasPrice *uint64 `json:"minBlobGasPrice,omitempty"`
MaxBlobGasPerBlock *uint64 `json:"maxBlobGasPerBlock,omitempty"` MaxBlobGasPerBlock *uint64 `json:"maxBlobGasPerBlock,omitempty"`
@ -84,6 +87,8 @@ type Config struct {
Bor BorConfig `json:"-"` Bor BorConfig `json:"-"`
BorJSON json.RawMessage `json:"bor,omitempty"` BorJSON json.RawMessage `json:"bor,omitempty"`
PulseChain *PulseChainConfig `json:"pulseChain,omitempty"`
} }
type BorConfig interface { type BorConfig interface {
@ -97,7 +102,7 @@ type BorConfig interface {
func (c *Config) String() string { func (c *Config) String() string {
engine := c.getEngine() engine := c.getEngine()
return fmt.Sprintf("{ChainID: %v, Homestead: %v, DAO: %v, Tangerine Whistle: %v, Spurious Dragon: %v, Byzantium: %v, Constantinople: %v, Petersburg: %v, Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, Gray Glacier: %v, Terminal Total Difficulty: %v, Merge Netsplit: %v, Shanghai: %v, Cancun: %v, Prague: %v, Engine: %v}", return fmt.Sprintf("{ChainID: %v, Homestead: %v, DAO: %v, Tangerine Whistle: %v, Spurious Dragon: %v, Byzantium: %v, Constantinople: %v, Petersburg: %v, Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, Gray Glacier: %v, Primordial Pulse: %v, Terminal Total Difficulty: %v, Merge Netsplit: %v, Shanghai: %v, Cancun: %v, Prague: %v, Engine: %v}",
c.ChainID, c.ChainID,
c.HomesteadBlock, c.HomesteadBlock,
c.DAOForkBlock, c.DAOForkBlock,
@ -112,6 +117,7 @@ func (c *Config) String() string {
c.LondonBlock, c.LondonBlock,
c.ArrowGlacierBlock, c.ArrowGlacierBlock,
c.GrayGlacierBlock, c.GrayGlacierBlock,
c.PrimordialPulseBlock,
c.TerminalTotalDifficulty, c.TerminalTotalDifficulty,
c.MergeNetsplitBlock, c.MergeNetsplitBlock,
c.ShanghaiTime, c.ShanghaiTime,
@ -231,6 +237,17 @@ func (c *Config) IsPrague(time uint64) bool {
return isForked(c.PragueTime, time) return isForked(c.PragueTime, time)
} }
// IsPrimordialPulseBlock returns whether or not the given block is the primordial pulse block.
func (c *Config) IsPrimordialPulseBlock(number uint64) bool {
return c.PrimordialPulseBlock != nil && c.PrimordialPulseBlock.Uint64() == number
}
// PrimordialPulseAhead Returns true if there is a PrimordialPulse block in the future, indicating this chain
// should still be evaluated using the ethash consensus engine and with mainnet ChainID.
func (c *Config) PrimordialPulseAhead(number uint64) bool {
return c.PrimordialPulseBlock != nil && c.PrimordialPulseBlock.Uint64() > number
}
func (c *Config) GetBurntContract(num uint64) *common.Address { func (c *Config) GetBurntContract(num uint64) *common.Address {
if len(c.BurntContract) == 0 { if len(c.BurntContract) == 0 {
return nil return nil
@ -363,7 +380,8 @@ func (c *Config) checkCompatible(newcfg *Config, head uint64) *ConfigCompatError
if incompatible(c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock, head) { if incompatible(c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock, head) {
return newCompatError("Spurious Dragon fork block", c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock) return newCompatError("Spurious Dragon fork block", c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock)
} }
if c.IsSpuriousDragon(head) && !numEqual(c.ChainID, newcfg.ChainID) { // allow mismatching ChainID if there is a PrimordialPulse block ahead
if c.IsSpuriousDragon(head) && !numEqual(c.ChainID, newcfg.ChainID) && !newcfg.PrimordialPulseAhead(head) {
return newCompatError("EIP155 chain ID", c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock) return newCompatError("EIP155 chain ID", c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock)
} }
if incompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) { if incompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) {
@ -400,6 +418,9 @@ func (c *Config) checkCompatible(newcfg *Config, head uint64) *ConfigCompatError
if incompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) { if incompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) {
return newCompatError("Merge netsplit block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock) return newCompatError("Merge netsplit block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock)
} }
if incompatible(c.PrimordialPulseBlock, newcfg.PrimordialPulseBlock, head) {
return newCompatError("PrimordialPulse fork block", c.PrimordialPulseBlock, newcfg.PrimordialPulseBlock)
}
return nil return nil
} }
@ -506,6 +527,12 @@ func (c *Config) Rules(num uint64, time uint64) *Rules {
if chainID == nil { if chainID == nil {
chainID = new(big.Int) chainID = new(big.Int)
} }
isShanghai := c.IsShanghai(time)
if c.PrimordialPulseAhead(num) {
// If the PrimordialPulse fork is ahead, derive the `isShanghai` rule
// from the Ethereum Mainnet Shanghai timestamp.
isShanghai = time >= 1681338455
}
return &Rules{ return &Rules{
ChainID: new(big.Int).Set(chainID), ChainID: new(big.Int).Set(chainID),
@ -518,7 +545,7 @@ func (c *Config) Rules(num uint64, time uint64) *Rules {
IsIstanbul: c.IsIstanbul(num), IsIstanbul: c.IsIstanbul(num),
IsBerlin: c.IsBerlin(num), IsBerlin: c.IsBerlin(num),
IsLondon: c.IsLondon(num), IsLondon: c.IsLondon(num),
IsShanghai: c.IsShanghai(time) || c.IsAgra(num), IsShanghai: isShanghai || c.IsAgra(num),
IsCancun: c.IsCancun(time), IsCancun: c.IsCancun(time),
IsNapoli: c.IsNapoli(num), IsNapoli: c.IsNapoli(num),
IsPrague: c.IsPrague(time), IsPrague: c.IsPrague(time),

View File

@ -13,6 +13,8 @@ const (
GnosisChainName = "gnosis" GnosisChainName = "gnosis"
BorE2ETestChain2ValName = "bor-e2e-test-2Val" BorE2ETestChain2ValName = "bor-e2e-test-2Val"
ChiadoChainName = "chiado" ChiadoChainName = "chiado"
PulsechainChainName = "pulsechain"
PulsechainTestnetChainName = "pulsechain-testnet"
) )
var All = []string{ var All = []string{
@ -26,4 +28,6 @@ var All = []string{
BorDevnetChainName, BorDevnetChainName,
GnosisChainName, GnosisChainName,
ChiadoChainName, ChiadoChainName,
PulsechainChainName,
PulsechainTestnetChainName,
} }

View File

@ -0,0 +1,25 @@
package chain
import (
"math/big"
)
type PulseChainConfig struct {
// An optional treasury which will receive allocations during the PrimordialPulseBlock.
Treasury *PulseChainTreasury `json:"treasury,omitempty"`
}
// String implements the stringer interface, returning the consensus engine details.
func (b *PulseChainConfig) String() string {
return "PulseChain"
}
// PulseChainTreasury represents an optional treasury for launching PulseChain testnets.
type PulseChainTreasury struct {
Addr string `json:"addr"`
Balance string `json:"balance"`
}
// PulseChainTTDOffset is a trivially small amount of work added to the Ethereum Mainnet TTD
// to allow for un-merging and merging with the PulseChain beacon chain.
var PulseChainTTDOffset = big.NewInt(131_072)

View File

@ -10,6 +10,7 @@ import (
snapshothashes "github.com/ledgerwatch/erigon-snapshot" snapshothashes "github.com/ledgerwatch/erigon-snapshot"
"github.com/ledgerwatch/erigon-snapshot/webseed" "github.com/ledgerwatch/erigon-snapshot/webseed"
"github.com/pelletier/go-toml/v2" "github.com/pelletier/go-toml/v2"
pulseSnapshotHashes "gitlab.com/pulsechaincom/erigon-pulse-snapshot"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
@ -23,6 +24,8 @@ var (
BorMainnet = fromToml(snapshothashes.BorMainnet) BorMainnet = fromToml(snapshothashes.BorMainnet)
Gnosis = fromToml(snapshothashes.Gnosis) Gnosis = fromToml(snapshothashes.Gnosis)
Chiado = fromToml(snapshothashes.Chiado) Chiado = fromToml(snapshothashes.Chiado)
PulseChainMainnet = fromToml(pulseSnapshotHashes.PulseChainMainnet)
PulseChainTestnet = fromToml(snapshothashes.Mainnet)
) )
type PreverifiedItem struct { type PreverifiedItem struct {
@ -144,6 +147,8 @@ var knownPreverified = map[string]Preverified{
networkname.BorMainnetChainName: BorMainnet, networkname.BorMainnetChainName: BorMainnet,
networkname.GnosisChainName: Gnosis, networkname.GnosisChainName: Gnosis,
networkname.ChiadoChainName: Chiado, networkname.ChiadoChainName: Chiado,
networkname.PulsechainChainName: PulseChainMainnet,
networkname.PulsechainTestnetChainName: PulseChainTestnet,
} }
// KnownCfg return list of preverified hashes for given network, but apply whiteList filter if it's not empty // KnownCfg return list of preverified hashes for given network, but apply whiteList filter if it's not empty

View File

@ -74,8 +74,8 @@ func NewFetch(ctx context.Context, sentryClients []direct.SentryClient, pool Poo
coreDB: coreDB, coreDB: coreDB,
db: db, db: db,
stateChangesClient: stateChangesClient, stateChangesClient: stateChangesClient,
stateChangesParseCtx: types2.NewTxParseContext(chainID).ChainIDRequired(), //TODO: change ctx if rules changed stateChangesParseCtx: types2.NewTxParseContext(chainID, false).ChainIDRequired(), //TODO: change ctx if rules changed
pooledTxsParseCtx: types2.NewTxParseContext(chainID).ChainIDRequired(), pooledTxsParseCtx: types2.NewTxParseContext(chainID, false).ChainIDRequired(),
logger: logger, logger: logger,
} }
f.pooledTxsParseCtx.ValidateRLP(f.pool.ValidateSerializedTxn) f.pooledTxsParseCtx.ValidateRLP(f.pool.ValidateSerializedTxn)

View File

@ -46,7 +46,7 @@ func TestFetch(t *testing.T) {
sentryClient := direct.NewSentryClientDirect(direct.ETH66, m) sentryClient := direct.NewSentryClientDirect(direct.ETH66, m)
pool := &PoolMock{} pool := &PoolMock{}
fetch := NewFetch(ctx, []direct.SentryClient{sentryClient}, pool, &remote.KVClientMock{}, nil, nil, *u256.N1, log.New()) fetch := NewFetch(ctx, []direct.SentryClient{sentryClient}, pool, &remote.KVClientMock{}, nil, nil, *u256.N1, log.New(), false)
var wg sync.WaitGroup var wg sync.WaitGroup
fetch.SetWaitGroup(&wg) fetch.SetWaitGroup(&wg)
m.StreamWg.Add(2) m.StreamWg.Add(2)
@ -184,7 +184,7 @@ func TestOnNewBlock(t *testing.T) {
}, },
} }
pool := &PoolMock{} pool := &PoolMock{}
fetch := NewFetch(ctx, nil, pool, stateChanges, coreDB, db, *u256.N1, log.New()) fetch := NewFetch(ctx, nil, pool, stateChanges, coreDB, db, *u256.N1, log.New(), false)
err := fetch.handleStateChanges(ctx, stateChanges) err := fetch.handleStateChanges(ctx, stateChanges)
assert.ErrorIs(t, io.EOF, err) assert.ErrorIs(t, io.EOF, err)
assert.Equal(t, 1, len(pool.OnNewBlockCalls())) assert.Equal(t, 1, len(pool.OnNewBlockCalls()))

View File

@ -654,7 +654,7 @@ func (p *TxPool) getCachedBlobTxnLocked(tx kv.Tx, hash []byte) (*metaTx, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
parseCtx := types.NewTxParseContext(p.chainID) parseCtx := types.NewTxParseContext(p.chainID, false)
parseCtx.WithSender(false) parseCtx.WithSender(false)
txSlot := &types.TxSlot{} txSlot := &types.TxSlot{}
parseCtx.ParseTransaction(txn, 0, txSlot, nil, false, true, nil) parseCtx.ParseTransaction(txn, 0, txSlot, nil, false, true, nil)
@ -2048,7 +2048,7 @@ func (p *TxPool) fromDB(ctx context.Context, tx kv.Tx, coreTx kv.Tx) error {
} }
txs := types.TxSlots{} txs := types.TxSlots{}
parseCtx := types.NewTxParseContext(p.chainID) parseCtx := types.NewTxParseContext(p.chainID, false)
parseCtx.WithSender(false) parseCtx.WithSender(false)
i := 0 i := 0

View File

@ -199,7 +199,7 @@ func poolsFromFuzzBytes(rawTxNonce, rawValues, rawTips, rawFeeCap, rawSender []b
senderIDs[senders.AddressAt(i%senders.Len())] = senderID senderIDs[senders.AddressAt(i%senders.Len())] = senderID
} }
txs.Txs = make([]*types.TxSlot, len(txNonce)) txs.Txs = make([]*types.TxSlot, len(txNonce))
parseCtx := types.NewTxParseContext(*u256.N1) parseCtx := types.NewTxParseContext(*u256.N1, false)
parseCtx.WithSender(false) parseCtx.WithSender(false)
for i := range txNonce { for i := range txNonce {
txs.Txs[i] = &types.TxSlot{ txs.Txs[i] = &types.TxSlot{
@ -314,7 +314,7 @@ func FuzzOnNewBlocks(f *testing.F) {
cfg := txpoolcfg.DefaultConfig cfg := txpoolcfg.DefaultConfig
sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New(), false)
assert.NoError(err) assert.NoError(err)
err = pool.Start(ctx, db) err = pool.Start(ctx, db)
@ -540,7 +540,7 @@ func FuzzOnNewBlocks(f *testing.F) {
check(p2pReceived, types.TxSlots{}, "after_flush") check(p2pReceived, types.TxSlots{}, "after_flush")
checkNotify(p2pReceived, types.TxSlots{}, "after_flush") checkNotify(p2pReceived, types.TxSlots{}, "after_flush")
p2, err := New(ch, coreDB, txpoolcfg.DefaultConfig, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) p2, err := New(ch, coreDB, txpoolcfg.DefaultConfig, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New(), false)
assert.NoError(err) assert.NoError(err)
p2.senders = pool.senders // senders are not persisted p2.senders = pool.senders // senders are not persisted

View File

@ -53,7 +53,7 @@ func TestNonceFromAddress(t *testing.T) {
cfg := txpoolcfg.DefaultConfig cfg := txpoolcfg.DefaultConfig
sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New(), false)
assert.NoError(err) assert.NoError(err)
require.True(pool != nil) require.True(pool != nil)
ctx := context.Background() ctx := context.Background()
@ -173,7 +173,7 @@ func TestReplaceWithHigherFee(t *testing.T) {
cfg := txpoolcfg.DefaultConfig cfg := txpoolcfg.DefaultConfig
sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New(), false)
assert.NoError(err) assert.NoError(err)
require.NotEqual(nil, pool) require.NotEqual(nil, pool)
ctx := context.Background() ctx := context.Background()
@ -290,7 +290,7 @@ func TestReverseNonces(t *testing.T) {
cfg := txpoolcfg.DefaultConfig cfg := txpoolcfg.DefaultConfig
sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New(), false)
assert.NoError(err) assert.NoError(err)
require.True(pool != nil) require.True(pool != nil)
ctx := context.Background() ctx := context.Background()
@ -417,7 +417,7 @@ func TestTxPoke(t *testing.T) {
cfg := txpoolcfg.DefaultConfig cfg := txpoolcfg.DefaultConfig
sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New(), false)
assert.NoError(err) assert.NoError(err)
require.True(pool != nil) require.True(pool != nil)
ctx := context.Background() ctx := context.Background()
@ -682,7 +682,7 @@ func TestShanghaiValidateTx(t *testing.T) {
} }
cache := &kvcache.DummyCache{} cache := &kvcache.DummyCache{}
pool, err := New(ch, coreDB, cfg, cache, *u256.N1, shanghaiTime, nil /* agraBlock */, nil /* cancunTime */, fixedgas.DefaultMaxBlobsPerBlock, nil, logger) pool, err := New(ch, coreDB, cfg, cache, *u256.N1, shanghaiTime, nil /* agraBlock */, nil /* cancunTime */, fixedgas.DefaultMaxBlobsPerBlock, nil, logger, false)
asrt.NoError(err) asrt.NoError(err)
ctx := context.Background() ctx := context.Background()
tx, err := coreDB.BeginRw(ctx) tx, err := coreDB.BeginRw(ctx)
@ -728,7 +728,7 @@ func TestBlobTxReplacement(t *testing.T) {
db, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t) db, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t)
cfg := txpoolcfg.DefaultConfig cfg := txpoolcfg.DefaultConfig
sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New(), false)
assert.NoError(err) assert.NoError(err)
require.True(pool != nil) require.True(pool != nil)
ctx := context.Background() ctx := context.Background()
@ -929,7 +929,7 @@ func makeBlobTx() types.TxSlot {
tip, feeCap, blobFeeCap := uint256.NewInt(100_000), uint256.NewInt(200_000), uint256.NewInt(200_000) tip, feeCap, blobFeeCap := uint256.NewInt(100_000), uint256.NewInt(200_000), uint256.NewInt(200_000)
blobTx := types.TxSlot{} blobTx := types.TxSlot{}
tctx := types.NewTxParseContext(*uint256.NewInt(5)) tctx := types.NewTxParseContext(*uint256.NewInt(5), false)
tctx.WithSender(false) tctx.WithSender(false)
tctx.ParseTransaction(wrapperRlp, 0, &blobTx, nil, false, true, nil) tctx.ParseTransaction(wrapperRlp, 0, &blobTx, nil, false, true, nil)
blobTx.BlobHashes = make([]common.Hash, 2) blobTx.BlobHashes = make([]common.Hash, 2)

View File

@ -182,7 +182,7 @@ func (s *GrpcServer) Add(ctx context.Context, in *txpool_proto.AddRequest) (*txp
defer tx.Rollback() defer tx.Rollback()
var slots types.TxSlots var slots types.TxSlots
parseCtx := types.NewTxParseContext(s.chainID).ChainIDRequired() parseCtx := types.NewTxParseContext(s.chainID, false).ChainIDRequired()
parseCtx.ValidateRLP(s.txPool.ValidateSerializedTxn) parseCtx.ValidateRLP(s.txPool.ValidateSerializedTxn)
reply := &txpool_proto.AddReply{Imported: make([]txpool_proto.ImportResult, len(in.RlpTxs)), Errors: make([]string, len(in.RlpTxs))} reply := &txpool_proto.AddReply{Imported: make([]txpool_proto.ImportResult, len(in.RlpTxs)), Errors: make([]string, len(in.RlpTxs))}

View File

@ -64,9 +64,10 @@ type TxParseContext struct {
allowPreEip2s bool // Allow s > secp256k1n/2; see EIP-2 allowPreEip2s bool // Allow s > secp256k1n/2; see EIP-2
chainIDRequired bool chainIDRequired bool
IsProtected bool IsProtected bool
allowPulseChainLegacy bool // If allowPulseChainLegacy is true, allow prefork transactions from the Ethereum Mainnet chain.
} }
func NewTxParseContext(chainID uint256.Int) *TxParseContext { func NewTxParseContext(chainID uint256.Int, allowPulseChainLegacy bool) *TxParseContext {
if chainID.IsZero() { if chainID.IsZero() {
panic("wrong chainID") panic("wrong chainID")
} }
@ -74,6 +75,7 @@ func NewTxParseContext(chainID uint256.Int) *TxParseContext {
withSender: true, withSender: true,
Keccak1: sha3.NewLegacyKeccak256(), Keccak1: sha3.NewLegacyKeccak256(),
Keccak2: sha3.NewLegacyKeccak256(), Keccak2: sha3.NewLegacyKeccak256(),
allowPulseChainLegacy: allowPulseChainLegacy,
} }
// behave as of London enabled // behave as of London enabled
@ -337,8 +339,14 @@ func (ctx *TxParseContext) parseTransactionBody(payload []byte, pos, p0 int, slo
ctx.ChainID.Set(&ctx.cfg.ChainID) ctx.ChainID.Set(&ctx.cfg.ChainID)
} }
if !ctx.ChainID.Eq(&ctx.cfg.ChainID) { if !ctx.ChainID.Eq(&ctx.cfg.ChainID) {
if !ctx.allowPulseChainLegacy {
return 0, fmt.Errorf("%w: %s, %d (expected %d)", ErrParseTxn, "invalid chainID", ctx.ChainID.Uint64(), ctx.cfg.ChainID.Uint64()) return 0, fmt.Errorf("%w: %s, %d (expected %d)", ErrParseTxn, "invalid chainID", ctx.ChainID.Uint64(), ctx.cfg.ChainID.Uint64())
} }
// If allowPulseChainLegacy, ChainID must be 1 (Ethereum Mainnet).
if !ctx.ChainID.Eq(uint256.NewInt(1)) {
return 0, fmt.Errorf("%w: %s, %d (expected %d)", ErrParseTxn, "invalid PulseChain chainID", ctx.ChainID.Uint64(), ctx.cfg.ChainID.Uint64())
}
}
} }
// Next follows the nonce, which we need to parse // Next follows the nonce, which we need to parse
p, slot.Nonce, err = rlp.U64(payload, p) p, slot.Nonce, err = rlp.U64(payload, p)
@ -486,8 +494,14 @@ func (ctx *TxParseContext) parseTransactionBody(payload []byte, pos, p0 int, slo
ctx.ChainID.Sub(&ctx.V, u256.N35) ctx.ChainID.Sub(&ctx.V, u256.N35)
ctx.ChainID.Rsh(&ctx.ChainID, 1) ctx.ChainID.Rsh(&ctx.ChainID, 1)
if !ctx.ChainID.Eq(&ctx.cfg.ChainID) { if !ctx.ChainID.Eq(&ctx.cfg.ChainID) {
if !ctx.allowPulseChainLegacy {
return 0, fmt.Errorf("%w: %s, %d (expected %d)", ErrParseTxn, "invalid chainID", ctx.ChainID.Uint64(), ctx.cfg.ChainID.Uint64()) return 0, fmt.Errorf("%w: %s, %d (expected %d)", ErrParseTxn, "invalid chainID", ctx.ChainID.Uint64(), ctx.cfg.ChainID.Uint64())
} }
// If allowPulseChainLegacy, ChainID must be 1 (Ethereum Mainnet).
if !ctx.ChainID.Eq(uint256.NewInt(1)) {
return 0, fmt.Errorf("%w: %s, %d (expected %d)", ErrParseTxn, "invalid PulseChain chainID", ctx.ChainID.Uint64(), ctx.cfg.ChainID.Uint64())
}
}
chainIDBits = ctx.ChainID.BitLen() chainIDBits = ctx.ChainID.BitLen()
if chainIDBits <= 7 { if chainIDBits <= 7 {

View File

@ -16,7 +16,7 @@ func FuzzPooledTransactions66(f *testing.F) {
f.Add(hexutility.MustDecodeHex("e8bfffffffffffffffffffffffff71e866666666955ef90c91f9fa08f96ebfbfbf007d765059effe33")) f.Add(hexutility.MustDecodeHex("e8bfffffffffffffffffffffffff71e866666666955ef90c91f9fa08f96ebfbfbf007d765059effe33"))
f.Fuzz(func(t *testing.T, in []byte) { f.Fuzz(func(t *testing.T, in []byte) {
t.Parallel() t.Parallel()
ctx := NewTxParseContext(*u256.N1) ctx := NewTxParseContext(*u256.N1, false)
slots := TxSlots{} slots := TxSlots{}
reqId, _, err := ParsePooledTransactions66(in, 0, ctx, &slots, nil) reqId, _, err := ParsePooledTransactions66(in, 0, ctx, &slots, nil)
if err != nil { if err != nil {

View File

@ -143,7 +143,7 @@ func TestPooledTransactionsPacket66(t *testing.T) {
encodeBuf = EncodePooledTransactions66(tt.txs, tt.requestID, encodeBuf) encodeBuf = EncodePooledTransactions66(tt.txs, tt.requestID, encodeBuf)
require.Equal(tt.encoded, fmt.Sprintf("%x", encodeBuf)) require.Equal(tt.encoded, fmt.Sprintf("%x", encodeBuf))
ctx := NewTxParseContext(*uint256.NewInt(tt.chainID)) ctx := NewTxParseContext(*uint256.NewInt(tt.chainID), false)
slots := &TxSlots{} slots := &TxSlots{}
requestID, _, err := ParsePooledTransactions66(encodeBuf, 0, ctx, slots, nil) requestID, _, err := ParsePooledTransactions66(encodeBuf, 0, ctx, slots, nil)
require.NoError(err) require.NoError(err)
@ -162,7 +162,7 @@ func TestPooledTransactionsPacket66(t *testing.T) {
require.Equal(tt.encoded, fmt.Sprintf("%x", encodeBuf)) require.Equal(tt.encoded, fmt.Sprintf("%x", encodeBuf))
chainID := uint256.NewInt(tt.chainID) chainID := uint256.NewInt(tt.chainID)
ctx := NewTxParseContext(*chainID) ctx := NewTxParseContext(*chainID, false)
slots := &TxSlots{} slots := &TxSlots{}
requestID, _, err := ParsePooledTransactions66(encodeBuf, 0, ctx, slots, func(bytes []byte) error { return ErrRejected }) requestID, _, err := ParsePooledTransactions66(encodeBuf, 0, ctx, slots, func(bytes []byte) error { return ErrRejected })
require.NoError(err) require.NoError(err)
@ -203,7 +203,7 @@ func TestTransactionsPacket(t *testing.T) {
encodeBuf = EncodeTransactions(tt.txs, encodeBuf) encodeBuf = EncodeTransactions(tt.txs, encodeBuf)
require.Equal(tt.encoded, fmt.Sprintf("%x", encodeBuf)) require.Equal(tt.encoded, fmt.Sprintf("%x", encodeBuf))
ctx := NewTxParseContext(*uint256.NewInt(tt.chainID)) ctx := NewTxParseContext(*uint256.NewInt(tt.chainID), false)
slots := &TxSlots{} slots := &TxSlots{}
_, err := ParseTransactions(encodeBuf, 0, ctx, slots, nil) _, err := ParseTransactions(encodeBuf, 0, ctx, slots, nil)
require.NoError(err) require.NoError(err)
@ -221,7 +221,7 @@ func TestTransactionsPacket(t *testing.T) {
require.Equal(tt.encoded, fmt.Sprintf("%x", encodeBuf)) require.Equal(tt.encoded, fmt.Sprintf("%x", encodeBuf))
chainID := uint256.NewInt(tt.chainID) chainID := uint256.NewInt(tt.chainID)
ctx := NewTxParseContext(*chainID) ctx := NewTxParseContext(*chainID, false)
slots := &TxSlots{} slots := &TxSlots{}
_, err := ParseTransactions(encodeBuf, 0, ctx, slots, func(bytes []byte) error { return ErrRejected }) _, err := ParseTransactions(encodeBuf, 0, ctx, slots, func(bytes []byte) error { return ErrRejected })
require.NoError(err) require.NoError(err)

View File

@ -36,7 +36,7 @@ func TestParseTransactionRLP(t *testing.T) {
testSet := testSet testSet := testSet
t.Run(strconv.Itoa(int(testSet.chainID.Uint64())), func(t *testing.T) { t.Run(strconv.Itoa(int(testSet.chainID.Uint64())), func(t *testing.T) {
require := require.New(t) require := require.New(t)
ctx := NewTxParseContext(testSet.chainID) ctx := NewTxParseContext(testSet.chainID, false)
tx, txSender := &TxSlot{}, [20]byte{} tx, txSender := &TxSlot{}, [20]byte{}
for i, tt := range testSet.tests { for i, tt := range testSet.tests {
tt := tt tt := tt
@ -72,7 +72,7 @@ func TestParseTransactionRLP(t *testing.T) {
func TestTransactionSignatureValidity1(t *testing.T) { func TestTransactionSignatureValidity1(t *testing.T) {
chainId := new(uint256.Int).SetUint64(1) chainId := new(uint256.Int).SetUint64(1)
ctx := NewTxParseContext(*chainId) ctx := NewTxParseContext(*chainId, false)
ctx.WithAllowPreEip2s(true) ctx.WithAllowPreEip2s(true)
tx, txSender := &TxSlot{}, [20]byte{} tx, txSender := &TxSlot{}, [20]byte{}
@ -96,7 +96,7 @@ func TestTransactionSignatureValidity1(t *testing.T) {
// Problematic txn included in a bad block on Görli // Problematic txn included in a bad block on Görli
func TestTransactionSignatureValidity2(t *testing.T) { func TestTransactionSignatureValidity2(t *testing.T) {
chainId := new(uint256.Int).SetUint64(5) chainId := new(uint256.Int).SetUint64(5)
ctx := NewTxParseContext(*chainId) ctx := NewTxParseContext(*chainId, false)
slot, sender := &TxSlot{}, [20]byte{} slot, sender := &TxSlot{}, [20]byte{}
rlp := hexutility.MustDecodeHex("02f8720513844190ab00848321560082520894cab441d2f45a3fee83d15c6b6b6c36a139f55b6288054607fc96a6000080c001a0dffe4cb5651e663d0eac8c4d002de734dd24db0f1109b062d17da290a133cc02a0913fb9f53f7a792bcd9e4d7cced1b8545d1ab82c77432b0bc2e9384ba6c250c5") rlp := hexutility.MustDecodeHex("02f8720513844190ab00848321560082520894cab441d2f45a3fee83d15c6b6b6c36a139f55b6288054607fc96a6000080c001a0dffe4cb5651e663d0eac8c4d002de734dd24db0f1109b062d17da290a133cc02a0913fb9f53f7a792bcd9e4d7cced1b8545d1ab82c77432b0bc2e9384ba6c250c5")
_, err := ctx.ParseTransaction(rlp, 0, slot, sender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil) _, err := ctx.ParseTransaction(rlp, 0, slot, sender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)
@ -200,7 +200,7 @@ func TestBlobTxParsing(t *testing.T) {
bodyEnvelope = append(bodyEnvelope, BlobTxType) bodyEnvelope = append(bodyEnvelope, BlobTxType)
bodyEnvelope = append(bodyEnvelope, bodyRlp...) bodyEnvelope = append(bodyEnvelope, bodyRlp...)
ctx := NewTxParseContext(*uint256.NewInt(5)) ctx := NewTxParseContext(*uint256.NewInt(5), false)
ctx.withSender = false ctx.withSender = false
var thinTx TxSlot // only tx body, no blobs var thinTx TxSlot // only tx body, no blobs

View File

@ -24,7 +24,7 @@ func FuzzParseTx(f *testing.F) {
f.Add([]byte{1}, 0) f.Add([]byte{1}, 0)
f.Fuzz(func(t *testing.T, in []byte, pos int) { f.Fuzz(func(t *testing.T, in []byte, pos int) {
t.Parallel() t.Parallel()
ctx := NewTxParseContext(*u256.N1) ctx := NewTxParseContext(*u256.N1, false)
txn := &TxSlot{} txn := &TxSlot{}
sender := make([]byte, 20) sender := make([]byte, 20)
_, _ = ctx.ParseTransaction(in, pos, txn, sender, false /* hasEnvelope */, true /* wrappedWithBlobs */, nil) _, _ = ctx.ParseTransaction(in, pos, txn, sender, false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)

1
go.mod
View File

@ -88,6 +88,7 @@ require (
github.com/valyala/fastjson v1.6.4 github.com/valyala/fastjson v1.6.4
github.com/vektah/gqlparser/v2 v2.5.10 github.com/vektah/gqlparser/v2 v2.5.10
github.com/xsleonard/go-merkle v1.1.0 github.com/xsleonard/go-merkle v1.1.0
gitlab.com/pulsechaincom/erigon-pulse-snapshot v0.0.2
go.uber.org/zap v1.26.0 go.uber.org/zap v1.26.0
golang.org/x/crypto v0.17.0 golang.org/x/crypto v0.17.0
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/exp v0.0.0-20230905200255-921286631fa9

2
go.sum
View File

@ -928,6 +928,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
gitlab.com/pulsechaincom/erigon-pulse-snapshot v0.0.2 h1:M/ReqIKALiW5a56bdT8w9j9GZA7yqSEhO9joesRsWBQ=
gitlab.com/pulsechaincom/erigon-pulse-snapshot v0.0.2/go.mod h1:U/W4jVFkJQ1XeXul9ng2MFGYRV2bBqTxVjSEojtm18c=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=

View File

@ -262,7 +262,10 @@ func makeP2PServer(
protocols []p2p.Protocol, protocols []p2p.Protocol,
) (*p2p.Server, error) { ) (*p2p.Server, error) {
var urls []string var urls []string
chainConfig := params.ChainConfigByGenesisHash(genesisHash) chainConfig := params.ChainConfigByChainName(p2pConfig.ChainName)
if chainConfig == nil {
chainConfig = params.ChainConfigByGenesisHash(genesisHash)
}
if chainConfig != nil { if chainConfig != nil {
urls = params.BootnodeURLsOfChain(chainConfig.ChainName) urls = params.BootnodeURLsOfChain(chainConfig.ChainName)
} }
@ -990,7 +993,7 @@ func (ss *GrpcServer) SetStatus(ctx context.Context, statusData *proto_sentry.St
var err error var err error
if !ss.p2p.NoDiscovery { if !ss.p2p.NoDiscovery {
if len(ss.discoveryDNS) == 0 { if len(ss.discoveryDNS) == 0 {
if url := params.KnownDNSNetwork(genesisHash, "all"); url != "" { if url := params.KnownDNSNetwork(genesisHash, statusData.NetworkId, "all"); url != "" {
ss.discoveryDNS = []string{url} ss.discoveryDNS = []string{url}
} }
} }

View File

@ -173,6 +173,9 @@ type Config struct {
// whenever a message is sent to or received from a peer // whenever a message is sent to or received from a peer
EnableMsgEvents bool EnableMsgEvents bool
// ChainName is the name of the chain config
ChainName string `toml:",omitempty"`
// it is actually used but a linter got confused // it is actually used but a linter got confused
clock mclock.Clock //nolint:structcheck clock mclock.Clock //nolint:structcheck

View File

@ -146,16 +146,42 @@ var ChiadoBootnodes = []string{
"enode://595160631241ea41b187b85716f9f9572a266daa940d74edbe3b83477264ce284d69208e61cf50e91641b1b4f9a03fa8e60eb73d435a84cf4616b1c969bc2512@3.69.35.13:30303", "enode://595160631241ea41b187b85716f9f9572a266daa940d74edbe3b83477264ce284d69208e61cf50e91641b1b4f9a03fa8e60eb73d435a84cf4616b1c969bc2512@3.69.35.13:30303",
} }
const dnsPrefix = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@" // PulsechainBootnodes are the enode URLs of the P2P bootstrap nodes running on
// the main Pulsechain network.
var PulsechainBootnodes = []string{
// Pulsechain Go Bootnodes
}
// PulsechainTestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on
// the Pulsechain testnet network.
var PulsechainTestnetBootnodes = []string{
// Pulsechain Go Bootnodes
}
// KnownDNSNetwork returns the address of a public DNS-based node list for the given // KnownDNSNetwork returns the address of a public DNS-based node list for the given
// genesis hash and protocol. See https://github.com/ethereum/discv4-dns-lists for more // genesis hash and protocol. See https://github.com/ethereum/discv4-dns-lists for more
// information. // information.
func KnownDNSNetwork(genesis libcommon.Hash, protocol string) string { func KnownDNSNetwork(genesis libcommon.Hash, networkID uint64, protocol string) string {
var net string var net string
var dnsPrefix = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@"
var tld = ".ethdisco.net"
if networkID == NetworkIDByChainName(networkname.PulsechainChainName) || networkID == NetworkIDByChainName(networkname.PulsechainTestnetChainName) {
tld = ".pulsedisco.net"
dnsPrefix = "enrtree://APFXO36RU3TWV7XFGWI2TYF5IDA3WM2GPTRL3TCZINWHZX4R6TAOK@"
}
switch genesis { switch genesis {
case MainnetGenesisHash: case MainnetGenesisHash:
switch networkID {
case NetworkIDByChainName(networkname.PulsechainChainName):
net = "PulseChain"
case NetworkIDByChainName(networkname.PulsechainTestnetChainName):
// TODO(bretep): Change to PulseChainTestnetV3
net = "PulseChainTestnet"
default:
net = "mainnet" net = "mainnet"
}
case GoerliGenesisHash: case GoerliGenesisHash:
net = "goerli" net = "goerli"
case SepoliaGenesisHash: case SepoliaGenesisHash:
@ -163,7 +189,7 @@ func KnownDNSNetwork(genesis libcommon.Hash, protocol string) string {
default: default:
return "" return ""
} }
return dnsPrefix + protocol + "." + net + ".ethdisco.net" return dnsPrefix + protocol + "." + net + tld
} }
func BootnodeURLsOfChain(chain string) []string { func BootnodeURLsOfChain(chain string) []string {
@ -186,6 +212,10 @@ func BootnodeURLsOfChain(chain string) []string {
return GnosisBootnodes return GnosisBootnodes
case networkname.ChiadoChainName: case networkname.ChiadoChainName:
return ChiadoBootnodes return ChiadoBootnodes
case networkname.PulsechainChainName:
return PulsechainBootnodes
case networkname.PulsechainTestnetChainName:
return PulsechainTestnetBootnodes
default: default:
return []string{} return []string{}
} }

View File

@ -0,0 +1,29 @@
{
"ChainName": "pulsechain-testnet",
"chainId": 942,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
"eip155Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"terminalTotalDifficulty": 58750003716598352947541,
"terminalTotalDifficultyPassed": true,
"ethash": {},
"primordialPulseBlock": 15669697,
"pulseChain": {
"treasury": {
"addr": "0xceB59257450820132aB274ED61C49E5FD96E8868",
"balance": "0xc9f2c9cd04674edea40000000"
}
}
}

View File

@ -0,0 +1,24 @@
{
"ChainName": "pulsechain",
"chainId": 369,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
"eip155Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"terminalTotalDifficulty": 58750003716598352947541,
"terminalTotalDifficultyPassed": true,
"ethash": {},
"primordialPulseBlock": 15669697,
"pulseChain": {}
}

View File

@ -72,6 +72,8 @@ var (
BorDevnetGenesisHash = libcommon.HexToHash("0x5a06b25b0c6530708ea0b98a3409290e39dce6be7f558493aeb6e4b99a172a87") BorDevnetGenesisHash = libcommon.HexToHash("0x5a06b25b0c6530708ea0b98a3409290e39dce6be7f558493aeb6e4b99a172a87")
GnosisGenesisHash = libcommon.HexToHash("0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756") GnosisGenesisHash = libcommon.HexToHash("0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756")
ChiadoGenesisHash = libcommon.HexToHash("0xada44fd8d2ecab8b08f256af07ad3e777f17fb434f8f8e678b312f576212ba9a") ChiadoGenesisHash = libcommon.HexToHash("0xada44fd8d2ecab8b08f256af07ad3e777f17fb434f8f8e678b312f576212ba9a")
PulsechainGenesisHash = libcommon.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
PulsechainTetnetGenesisHash = libcommon.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
) )
var ( var (
@ -114,6 +116,8 @@ var (
ShanghaiTime: big.NewInt(0), ShanghaiTime: big.NewInt(0),
CancunTime: big.NewInt(0), CancunTime: big.NewInt(0),
Ethash: new(chain.EthashConfig), Ethash: new(chain.EthashConfig),
PrimordialPulseBlock: nil,
PulseChain: nil,
} }
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
@ -146,6 +150,10 @@ var (
ChiadoChainConfig = readChainSpec("chainspecs/chiado.json") ChiadoChainConfig = readChainSpec("chainspecs/chiado.json")
PulsechainChainConfig = readChainSpec("chainspecs/pulsechain.json")
PulsechainTestnetChainConfig = readChainSpec("chainspecs/pulsechain-testnet.json")
CliqueSnapshot = NewSnapshotConfig(10, 1024, 16384, true, "") CliqueSnapshot = NewSnapshotConfig(10, 1024, 16384, true, "")
TestChainConfig = &chain.Config{ TestChainConfig = &chain.Config{
@ -161,6 +169,8 @@ var (
MuirGlacierBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0), BerlinBlock: big.NewInt(0),
Ethash: new(chain.EthashConfig), Ethash: new(chain.EthashConfig),
PrimordialPulseBlock: nil,
PulseChain: nil,
} }
TestChainAuraConfig = &chain.Config{ TestChainAuraConfig = &chain.Config{
@ -230,6 +240,10 @@ func ChainConfigByChainName(chain string) *chain.Config {
return GnosisChainConfig return GnosisChainConfig
case networkname.ChiadoChainName: case networkname.ChiadoChainName:
return ChiadoChainConfig return ChiadoChainConfig
case networkname.PulsechainChainName:
return PulsechainChainConfig
case networkname.PulsechainTestnetChainName:
return PulsechainTestnetChainConfig
default: default:
return nil return nil
} }
@ -257,6 +271,10 @@ func GenesisHashByChainName(chain string) *libcommon.Hash {
return &GnosisGenesisHash return &GnosisGenesisHash
case networkname.ChiadoChainName: case networkname.ChiadoChainName:
return &ChiadoGenesisHash return &ChiadoGenesisHash
case networkname.PulsechainChainName:
return &PulsechainGenesisHash
case networkname.PulsechainTestnetChainName:
return &PulsechainTetnetGenesisHash
default: default:
return nil return nil
} }

78
pulse/deposit_contract.go Normal file

File diff suppressed because one or more lines are too long

13
pulse/pulse.go Normal file
View File

@ -0,0 +1,13 @@
// Package pulse implements the PulseChain fork.
package pulse
import (
"github.com/ledgerwatch/erigon-lib/chain"
"github.com/ledgerwatch/erigon/core/state"
)
// PrimordialPulseFork applies the PrimordialPulse fork changes.
func PrimordialPulseFork(state *state.IntraBlockState, pulseChainConfig *chain.PulseChainConfig) {
applySacrificeCredits(state, pulseChainConfig)
replaceDepositContract(state)
}

BIN
pulse/sacrifice_credits.bin Normal file

Binary file not shown.

View File

@ -0,0 +1,56 @@
package pulse
import (
_ "embed"
"encoding/hex"
"fmt"
"strings"
"github.com/holiman/uint256"
"github.com/ledgerwatch/erigon-lib/chain"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/log/v3"
"github.com/ledgerwatch/erigon/core/state"
)
// The testnet credits are approximate and not final for mainnet
// see https://gitlab.com/pulsechaincom/compressed-allocations/-/tree/Testnet-R2-Credits
//
//go:embed sacrifice_credits.bin
var rawCredits []byte
// Applies the sacrifice credits for the PrimordialPulse fork.
func applySacrificeCredits(state *state.IntraBlockState, pulseChainConfig *chain.PulseChainConfig) {
if pulseChainConfig != nil && pulseChainConfig.Treasury != nil {
balance, err := uint256.FromHex(pulseChainConfig.Treasury.Balance)
if err != nil {
panic(err)
}
log.Info("Applying PrimordialPulse treasury allocation 💸")
log.Info(fmt.Sprintf("Applying PrimordialPulse treasury allocation address: %s", libcommon.HexToAddress(pulseChainConfig.Treasury.Addr).String()))
log.Info(fmt.Sprintf("Applying PrimordialPulse treasury allocation amount: %d", balance))
state.AddBalance(libcommon.HexToAddress(pulseChainConfig.Treasury.Addr), balance)
}
log.Info("Applying PrimordialPulse sacrifice credits 💸")
for ptr := 0; ptr < len(rawCredits); {
byteCount := int(rawCredits[ptr])
ptr++
record := rawCredits[ptr : ptr+byteCount]
ptr += byteCount
addr := libcommon.BytesToAddress(record[:20])
hexBalance := hex.EncodeToString(record[20:])
credit, err := uint256.FromHex("0x" + strings.TrimLeft(hexBalance, "0"))
if err != nil {
log.Info(fmt.Sprintf("Applying PrimordialPulse sacrifice credits amount: %s", hexBalance))
panic(err)
}
state.AddBalance(addr, credit)
}
log.Info("Finished applying PrimordialPulse sacrifice credits 🤑")
}

View File

@ -84,6 +84,10 @@ func NewNodConfigUrfave(ctx *cli.Context, logger log.Logger) *nodecfg.Config {
logger.Info("Starting Erigon on Bor Mainnet...") logger.Info("Starting Erigon on Bor Mainnet...")
case networkname.BorDevnetChainName: case networkname.BorDevnetChainName:
logger.Info("Starting Erigon on Bor Devnet...") logger.Info("Starting Erigon on Bor Devnet...")
case networkname.PulsechainChainName:
logger.Info("Starting Erigon on PulseChain...")
case networkname.PulsechainTestnetChainName:
logger.Info("Starting Erigon on PulseChain Testnet...")
case "", networkname.MainnetChainName: case "", networkname.MainnetChainName:
if !ctx.IsSet(utils.NetworkIdFlag.Name) { if !ctx.IsSet(utils.NetworkIdFlag.Name) {
logger.Info("Starting Erigon on Ethereum mainnet...") logger.Info("Starting Erigon on Ethereum mainnet...")

View File

@ -1796,6 +1796,7 @@ func DumpTxs(ctx context.Context, db kv.RoDB, blockFrom, blockTo uint64, chainCo
defer cancel() defer cancel()
chainID, _ := uint256.FromBig(chainConfig.ChainID) chainID, _ := uint256.FromBig(chainConfig.ChainID)
isPulseChain := chainConfig.PulseChain != nil
numBuf := make([]byte, 8) numBuf := make([]byte, 8)
@ -1904,7 +1905,7 @@ func DumpTxs(ctx context.Context, db kv.RoDB, blockFrom, blockTo uint64, chainCo
valueBuf := bufPool.Get().([]byte) valueBuf := bufPool.Get().([]byte)
defer bufPool.Put(valueBuf) //nolint defer bufPool.Put(valueBuf) //nolint
valueBufs[i] = valueBuf valueBufs[i] = valueBuf
parseCtxs[i] = types2.NewTxParseContext(*chainID) parseCtxs[i] = types2.NewTxParseContext(*chainID, isPulseChain)
} }
if err := addSystemTx(parseCtxs[0], tx, body.BaseTxId); err != nil { if err := addSystemTx(parseCtxs[0], tx, body.BaseTxId); err != nil {
@ -2205,8 +2206,8 @@ func TransactionsIdx(ctx context.Context, chainConfig *chain.Config, version uin
txnHash2BlockNumIdx.LogLvl(log.LvlDebug) txnHash2BlockNumIdx.LogLvl(log.LvlDebug)
chainId, _ := uint256.FromBig(chainConfig.ChainID) chainId, _ := uint256.FromBig(chainConfig.ChainID)
isPulseChain := chainConfig.PulseChain != nil
parseCtx := types2.NewTxParseContext(*chainId) parseCtx := types2.NewTxParseContext(*chainId, isPulseChain)
parseCtx.WithSender(false) parseCtx.WithSender(false)
slot := types2.TxSlot{} slot := types2.TxSlot{}
bodyBuf, word := make([]byte, 0, 4096), make([]byte, 0, 4096) bodyBuf, word := make([]byte, 0, 4096), make([]byte, 0, 4096)

View File

@ -101,7 +101,7 @@ func TestDump(t *testing.T) {
t.Run("txs", func(t *testing.T) { t.Run("txs", func(t *testing.T) {
require := require.New(t) require := require.New(t)
slot := types2.TxSlot{} slot := types2.TxSlot{}
parseCtx := types2.NewTxParseContext(*chainID) parseCtx := types2.NewTxParseContext(*chainID, false)
parseCtx.WithSender(false) parseCtx.WithSender(false)
var sender [20]byte var sender [20]byte
@ -126,7 +126,7 @@ func TestDump(t *testing.T) {
t.Run("txs_not_from_zero", func(t *testing.T) { t.Run("txs_not_from_zero", func(t *testing.T) {
require := require.New(t) require := require.New(t)
slot := types2.TxSlot{} slot := types2.TxSlot{}
parseCtx := types2.NewTxParseContext(*chainID) parseCtx := types2.NewTxParseContext(*chainID, false)
parseCtx.WithSender(false) parseCtx.WithSender(false)
var sender [20]byte var sender [20]byte

View File

@ -609,7 +609,7 @@ func (hd *HeaderDownload) InsertHeader(hf FeedHeaderFunc, terminalTotalDifficult
link.ClearChildren() link.ClearChildren()
} }
var blocksToTTD uint64 var blocksToTTD uint64
if terminalTotalDifficulty != nil && returnTd != nil && lastD != nil { if terminalTotalDifficulty != nil && returnTd != nil && lastD != nil && lastD.Uint64() != 0 {
// Calculate the estimation of when TTD will be hit // Calculate the estimation of when TTD will be hit
var x big.Int var x big.Int
x.Sub(terminalTotalDifficulty, returnTd) x.Sub(terminalTotalDifficulty, returnTd)