all: implement EIP-7002 & EIP-7251 (#30571)
This is a redo of #29052 based on newer specs. Here we implement EIPs scheduled for the Prague fork: - EIP-7002: Execution layer triggerable withdrawals - EIP-7251: Increase the MAX_EFFECTIVE_BALANCE Co-authored-by: lightclient <lightclient@protonmail.com>
This commit is contained in:
parent
16bf471151
commit
3a5313f3f3
|
@ -66,7 +66,7 @@ type ExecutionResult struct {
|
||||||
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
|
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
|
||||||
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
||||||
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
|
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
|
||||||
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
|
RequestsHash *common.Hash `json:"requestsHash,omitempty"`
|
||||||
Requests [][]byte `json:"requests,omitempty"`
|
Requests [][]byte `json:"requests,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,8 +379,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
|
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
|
||||||
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
|
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var requests [][]byte
|
||||||
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
|
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
|
||||||
// Parse the requests from the logs
|
// EIP-6110 deposits
|
||||||
var allLogs []*types.Log
|
var allLogs []*types.Log
|
||||||
for _, receipt := range receipts {
|
for _, receipt := range receipts {
|
||||||
allLogs = append(allLogs, receipt.Logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
|
@ -389,12 +391,23 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
|
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
|
||||||
}
|
}
|
||||||
requests := [][]byte{depositRequests}
|
requests = append(requests, depositRequests)
|
||||||
// Calculate the requests root
|
// create EVM for system calls
|
||||||
|
vmenv := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
||||||
|
// EIP-7002 withdrawals
|
||||||
|
withdrawalRequests := core.ProcessWithdrawalQueue(vmenv, statedb)
|
||||||
|
requests = append(requests, withdrawalRequests)
|
||||||
|
// EIP-7251 consolidations
|
||||||
|
consolidationRequests := core.ProcessConsolidationQueue(vmenv, statedb)
|
||||||
|
requests = append(requests, consolidationRequests)
|
||||||
|
}
|
||||||
|
if requests != nil {
|
||||||
|
// Set requestsHash on block.
|
||||||
h := types.CalcRequestsHash(requests)
|
h := types.CalcRequestsHash(requests)
|
||||||
execRs.RequestsHash = &h
|
execRs.RequestsHash = &h
|
||||||
execRs.Requests = requests
|
execRs.Requests = requests
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-create statedb instance with new root upon the updated database
|
// Re-create statedb instance with new root upon the updated database
|
||||||
// for accessing latest states.
|
// for accessing latest states.
|
||||||
statedb, err = state.New(root, statedb.Database())
|
statedb, err = state.New(root, statedb.Database())
|
||||||
|
|
|
@ -4227,3 +4227,87 @@ func TestEIP3651(t *testing.T) {
|
||||||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7
|
||||||
|
var depositsGeneratorCode = common.FromHex("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033")
|
||||||
|
|
||||||
|
// This is a smoke test for EIP-7685 requests added in the Prague fork. The test first
|
||||||
|
// creates a block containing requests, and then inserts it into the chain to run
|
||||||
|
// validation.
|
||||||
|
func TestPragueRequests(t *testing.T) {
|
||||||
|
var (
|
||||||
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
|
config = *params.MergedTestChainConfig
|
||||||
|
signer = types.LatestSigner(&config)
|
||||||
|
engine = beacon.NewFaker()
|
||||||
|
)
|
||||||
|
gspec := &Genesis{
|
||||||
|
Config: &config,
|
||||||
|
Alloc: types.GenesisAlloc{
|
||||||
|
addr1: {Balance: big.NewInt(9999900000000000)},
|
||||||
|
config.DepositContractAddress: {Code: depositsGeneratorCode},
|
||||||
|
params.WithdrawalQueueAddress: {Code: params.WithdrawalQueueCode},
|
||||||
|
params.ConsolidationQueueAddress: {Code: params.ConsolidationQueueCode},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
|
||||||
|
// create deposit
|
||||||
|
depositTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
|
||||||
|
ChainID: gspec.Config.ChainID,
|
||||||
|
Nonce: 0,
|
||||||
|
To: &config.DepositContractAddress,
|
||||||
|
Gas: 500_000,
|
||||||
|
GasFeeCap: newGwei(5),
|
||||||
|
GasTipCap: big.NewInt(2),
|
||||||
|
})
|
||||||
|
b.AddTx(depositTx)
|
||||||
|
|
||||||
|
// create withdrawal request
|
||||||
|
withdrawalTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
|
||||||
|
ChainID: gspec.Config.ChainID,
|
||||||
|
Nonce: 1,
|
||||||
|
To: ¶ms.WithdrawalQueueAddress,
|
||||||
|
Gas: 500_000,
|
||||||
|
GasFeeCap: newGwei(5),
|
||||||
|
GasTipCap: big.NewInt(2),
|
||||||
|
Value: newGwei(1),
|
||||||
|
Data: common.FromHex("b917cfdc0d25b72d55cf94db328e1629b7f4fde2c30cdacf873b664416f76a0c7f7cc50c9f72a3cb84be88144cde91250000000000000d80"),
|
||||||
|
})
|
||||||
|
b.AddTx(withdrawalTx)
|
||||||
|
|
||||||
|
// create consolidation request
|
||||||
|
consolidationTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
|
||||||
|
ChainID: gspec.Config.ChainID,
|
||||||
|
Nonce: 2,
|
||||||
|
To: ¶ms.ConsolidationQueueAddress,
|
||||||
|
Gas: 500_000,
|
||||||
|
GasFeeCap: newGwei(5),
|
||||||
|
GasTipCap: big.NewInt(2),
|
||||||
|
Value: newGwei(1),
|
||||||
|
Data: common.FromHex("b917cfdc0d25b72d55cf94db328e1629b7f4fde2c30cdacf873b664416f76a0c7f7cc50c9f72a3cb84be88144cde9125b9812f7d0b1f2f969b52bbb2d316b0c2fa7c9dba85c428c5e6c27766bcc4b0c6e874702ff1eb1c7024b08524a9771601"),
|
||||||
|
})
|
||||||
|
b.AddTx(consolidationTx)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check block has the correct requests hash.
|
||||||
|
rh := blocks[0].RequestsHash()
|
||||||
|
if rh == nil {
|
||||||
|
t.Fatal("block has nil requests hash")
|
||||||
|
}
|
||||||
|
expectedRequestsHash := common.HexToHash("0x06ffb72b9f0823510b128bca6cd4f96f59b745de6791e9fc350b596e7605101e")
|
||||||
|
if *rh != expectedRequestsHash {
|
||||||
|
t.Fatalf("block has wrong requestsHash %v, want %v", *rh, expectedRequestsHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert block to check validation.
|
||||||
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
defer chain.Stop()
|
||||||
|
if n, err := chain.InsertChain(blocks); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -348,6 +348,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
|
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if config.IsPrague(b.header.Number, b.header.Time) {
|
if config.IsPrague(b.header.Number, b.header.Time) {
|
||||||
|
// EIP-6110 deposits
|
||||||
var blockLogs []*types.Log
|
var blockLogs []*types.Log
|
||||||
for _, r := range b.receipts {
|
for _, r := range b.receipts {
|
||||||
blockLogs = append(blockLogs, r.Logs...)
|
blockLogs = append(blockLogs, r.Logs...)
|
||||||
|
@ -357,6 +358,15 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
|
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
requests = append(requests, depositRequests)
|
||||||
|
// create EVM for system calls
|
||||||
|
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
|
||||||
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, cm.config, vm.Config{})
|
||||||
|
// EIP-7002 withdrawals
|
||||||
|
withdrawalRequests := ProcessWithdrawalQueue(vmenv, statedb)
|
||||||
|
requests = append(requests, withdrawalRequests)
|
||||||
|
// EIP-7251 consolidations
|
||||||
|
consolidationRequests := ProcessConsolidationQueue(vmenv, statedb)
|
||||||
|
requests = append(requests, consolidationRequests)
|
||||||
}
|
}
|
||||||
if requests != nil {
|
if requests != nil {
|
||||||
reqHash := types.CalcRequestsHash(requests)
|
reqHash := types.CalcRequestsHash(requests)
|
||||||
|
|
|
@ -472,7 +472,7 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if conf.IsPrague(num, g.Timestamp) {
|
if conf.IsPrague(num, g.Timestamp) {
|
||||||
emptyRequests := [][]byte{{0}}
|
emptyRequests := [][]byte{{0x00}, {0x01}, {0x02}}
|
||||||
rhash := types.CalcRequestsHash(emptyRequests)
|
rhash := types.CalcRequestsHash(emptyRequests)
|
||||||
head.RequestsHash = &rhash
|
head.RequestsHash = &rhash
|
||||||
}
|
}
|
||||||
|
@ -588,10 +588,11 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
||||||
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
||||||
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
||||||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||||
// Pre-deploy EIP-4788 system contract
|
// Pre-deploy system contracts
|
||||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||||
// Pre-deploy EIP-2935 history contract.
|
|
||||||
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
|
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
|
||||||
|
params.WithdrawalQueueAddress: {Nonce: 1, Code: params.WithdrawalQueueCode, Balance: common.Big0},
|
||||||
|
params.ConsolidationQueueAddress: {Nonce: 1, Code: params.ConsolidationQueueCode, Balance: common.Big0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if faucet != nil {
|
if faucet != nil {
|
||||||
|
|
|
@ -102,11 +102,18 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
// Read requests if Prague is enabled.
|
// Read requests if Prague is enabled.
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if p.config.IsPrague(block.Number(), block.Time()) {
|
if p.config.IsPrague(block.Number(), block.Time()) {
|
||||||
|
// EIP-6110 deposits
|
||||||
depositRequests, err := ParseDepositLogs(allLogs, p.config)
|
depositRequests, err := ParseDepositLogs(allLogs, p.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
requests = append(requests, depositRequests)
|
||||||
|
// EIP-7002 withdrawals
|
||||||
|
withdrawalRequests := ProcessWithdrawalQueue(vmenv, statedb)
|
||||||
|
requests = append(requests, withdrawalRequests)
|
||||||
|
// EIP-7251 consolidations
|
||||||
|
consolidationRequests := ProcessConsolidationQueue(vmenv, statedb)
|
||||||
|
requests = append(requests, consolidationRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||||
|
@ -219,9 +226,6 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
|
||||||
defer tracer.OnSystemCallEnd()
|
defer tracer.OnSystemCallEnd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
|
|
||||||
// the new root
|
|
||||||
msg := &Message{
|
msg := &Message{
|
||||||
From: params.SystemAddress,
|
From: params.SystemAddress,
|
||||||
GasLimit: 30_000_000,
|
GasLimit: 30_000_000,
|
||||||
|
@ -248,7 +252,6 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.
|
||||||
defer tracer.OnSystemCallEnd()
|
defer tracer.OnSystemCallEnd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := &Message{
|
msg := &Message{
|
||||||
From: params.SystemAddress,
|
From: params.SystemAddress,
|
||||||
GasLimit: 30_000_000,
|
GasLimit: 30_000_000,
|
||||||
|
@ -264,6 +267,48 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.
|
||||||
statedb.Finalise(true)
|
statedb.Finalise(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
|
||||||
|
// It returns the opaque request data returned by the contract.
|
||||||
|
func ProcessWithdrawalQueue(vmenv *vm.EVM, statedb *state.StateDB) []byte {
|
||||||
|
return processRequestsSystemCall(vmenv, statedb, 0x01, params.WithdrawalQueueAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract.
|
||||||
|
// It returns the opaque request data returned by the contract.
|
||||||
|
func ProcessConsolidationQueue(vmenv *vm.EVM, statedb *state.StateDB) []byte {
|
||||||
|
return processRequestsSystemCall(vmenv, statedb, 0x02, params.ConsolidationQueueAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processRequestsSystemCall(vmenv *vm.EVM, statedb *state.StateDB, requestType byte, addr common.Address) []byte {
|
||||||
|
if tracer := vmenv.Config.Tracer; tracer != nil {
|
||||||
|
if tracer.OnSystemCallStart != nil {
|
||||||
|
tracer.OnSystemCallStart()
|
||||||
|
}
|
||||||
|
if tracer.OnSystemCallEnd != nil {
|
||||||
|
defer tracer.OnSystemCallEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &Message{
|
||||||
|
From: params.SystemAddress,
|
||||||
|
GasLimit: 30_000_000,
|
||||||
|
GasPrice: common.Big0,
|
||||||
|
GasFeeCap: common.Big0,
|
||||||
|
GasTipCap: common.Big0,
|
||||||
|
To: &addr,
|
||||||
|
}
|
||||||
|
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
||||||
|
statedb.AddAddressToAccessList(addr)
|
||||||
|
ret, _, _ := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
|
statedb.Finalise(true)
|
||||||
|
|
||||||
|
// Create withdrawals requestsData with prefix 0x01
|
||||||
|
requestsData := make([]byte, len(ret)+1)
|
||||||
|
requestsData[0] = requestType
|
||||||
|
copy(requestsData[1:], ret)
|
||||||
|
return requestsData
|
||||||
|
}
|
||||||
|
|
||||||
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
||||||
// BeaconDepositContract.
|
// BeaconDepositContract.
|
||||||
func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, error) {
|
func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, error) {
|
||||||
|
|
|
@ -403,6 +403,7 @@ func (b *Block) BaseFee() *big.Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot }
|
func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot }
|
||||||
|
func (b *Block) RequestsHash() *common.Hash { return b.header.RequestsHash }
|
||||||
|
|
||||||
func (b *Block) ExcessBlobGas() *uint64 {
|
func (b *Block) ExcessBlobGas() *uint64 {
|
||||||
var excessBlobGas *uint64
|
var excessBlobGas *uint64
|
||||||
|
|
|
@ -220,7 +220,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Mark the payload as canon
|
// Mark the payload as canon
|
||||||
if _, err = c.engineAPI.NewPayloadV3(*payload, blobHashes, &common.Hash{}); err != nil {
|
if _, err = c.engineAPI.NewPayloadV4(*payload, blobHashes, &common.Hash{}, envelope.Requests); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.setCurrentState(payload.BlockHash, finalizedHash)
|
c.setCurrentState(payload.BlockHash, finalizedHash)
|
||||||
|
|
|
@ -40,7 +40,7 @@ func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis, period
|
||||||
|
|
||||||
n, err := node.New(&node.Config{
|
n, err := node.New(&node.Config{
|
||||||
P2P: p2p.Config{
|
P2P: p2p.Config{
|
||||||
ListenAddr: "127.0.0.1:8545",
|
ListenAddr: "127.0.0.1:0",
|
||||||
NoDiscovery: true,
|
NoDiscovery: true,
|
||||||
MaxPeers: 0,
|
MaxPeers: 0,
|
||||||
},
|
},
|
||||||
|
|
|
@ -86,7 +86,7 @@ func TestSupplyOmittedFields(t *testing.T) {
|
||||||
|
|
||||||
expected := supplyInfo{
|
expected := supplyInfo{
|
||||||
Number: 0,
|
Number: 0,
|
||||||
Hash: common.HexToHash("0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703"),
|
Hash: common.HexToHash("0xc02ee8ee5b54a40e43f0fa827d431e1bd4f217e941790dda10b2521d1925a20b"),
|
||||||
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||||
}
|
}
|
||||||
actual := out[expected.Number]
|
actual := out[expected.Number]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
"blobGasPrice": "0x1",
|
"blobGasPrice": "0x1",
|
||||||
"blobGasUsed": "0x20000",
|
"blobGasUsed": "0x20000",
|
||||||
"blockHash": "0xd1392771155ce83f6403c6af275efd22bed567030c21168fcc9dbad5004eb245",
|
"blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d",
|
||||||
"blockNumber": "0x6",
|
"blockNumber": "0x6",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"blockHash": "0x56ea26cf955d7f2e08e194ad212ca4d5f99ee8e0b19dec3c71d8faafa33b1d22",
|
"blockHash": "0x5526cd89bc188f20fd5e9bb50d8054dc5a51a81a74ed07eacf36a4a8b10de4b1",
|
||||||
"blockNumber": "0x2",
|
"blockNumber": "0x2",
|
||||||
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
|
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
|
||||||
"cumulativeGasUsed": "0xcf50",
|
"cumulativeGasUsed": "0xcf50",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"blockHash": "0xf41e7a7a716382f20464cf76c6ae1fa701e9d32f5cc550ebfd2391b9642ae6bc",
|
"blockHash": "0x3e946aa9e252873af511b257d9d89a1bcafa54ce7c6a6442f8407ecdf81e288d",
|
||||||
"blockNumber": "0x4",
|
"blockNumber": "0x4",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x538d",
|
"cumulativeGasUsed": "0x538d",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"blockHash": "0xa1410af902e98b32e0bbe464f8637ff464f1d4344b585127d2ce71f9cb39cb8a",
|
"blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f",
|
||||||
"blockNumber": "0x3",
|
"blockNumber": "0x3",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5e28",
|
"cumulativeGasUsed": "0x5e28",
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
"blockNumber": "0x3",
|
"blockNumber": "0x3",
|
||||||
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
|
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
|
||||||
"transactionIndex": "0x0",
|
"transactionIndex": "0x0",
|
||||||
"blockHash": "0xa1410af902e98b32e0bbe464f8637ff464f1d4344b585127d2ce71f9cb39cb8a",
|
"blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f",
|
||||||
"logIndex": "0x0",
|
"logIndex": "0x0",
|
||||||
"removed": false
|
"removed": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"blockHash": "0x797d0c5603eccb33cc8ebd1300e977746512ec49e6b89087c7aad28ff760a26f",
|
"blockHash": "0xda50d57d8802553b00bb8e4d777bd5c4114086941119ca04edb15429f4818ed9",
|
||||||
"blockNumber": "0x1",
|
"blockNumber": "0x1",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
"blobGasPrice": "0x1",
|
"blobGasPrice": "0x1",
|
||||||
"blobGasUsed": "0x20000",
|
"blobGasUsed": "0x20000",
|
||||||
"blockHash": "0xd1392771155ce83f6403c6af275efd22bed567030c21168fcc9dbad5004eb245",
|
"blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d",
|
||||||
"blockNumber": "0x6",
|
"blockNumber": "0x6",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"blobGasPrice": "0x1",
|
"blobGasPrice": "0x1",
|
||||||
"blobGasUsed": "0x20000",
|
"blobGasUsed": "0x20000",
|
||||||
"blockHash": "0xd1392771155ce83f6403c6af275efd22bed567030c21168fcc9dbad5004eb245",
|
"blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d",
|
||||||
"blockNumber": "0x6",
|
"blockNumber": "0x6",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0x56ea26cf955d7f2e08e194ad212ca4d5f99ee8e0b19dec3c71d8faafa33b1d22",
|
"blockHash": "0x5526cd89bc188f20fd5e9bb50d8054dc5a51a81a74ed07eacf36a4a8b10de4b1",
|
||||||
"blockNumber": "0x2",
|
"blockNumber": "0x2",
|
||||||
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
|
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
|
||||||
"cumulativeGasUsed": "0xcf50",
|
"cumulativeGasUsed": "0xcf50",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0x69bf6ba924d95b6c50b0357768e5c892bd1b00cdf2f97e2e81fc06a76dfa57e3",
|
"blockHash": "0xa04ad6be58c45fe483991b89416572bc50426b0de44b769757e95c704250f874",
|
||||||
"blockNumber": "0x5",
|
"blockNumber": "0x5",
|
||||||
"contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18",
|
"contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18",
|
||||||
"cumulativeGasUsed": "0xe01c",
|
"cumulativeGasUsed": "0xe01c",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0xf41e7a7a716382f20464cf76c6ae1fa701e9d32f5cc550ebfd2391b9642ae6bc",
|
"blockHash": "0x3e946aa9e252873af511b257d9d89a1bcafa54ce7c6a6442f8407ecdf81e288d",
|
||||||
"blockNumber": "0x4",
|
"blockNumber": "0x4",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x538d",
|
"cumulativeGasUsed": "0x538d",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0x797d0c5603eccb33cc8ebd1300e977746512ec49e6b89087c7aad28ff760a26f",
|
"blockHash": "0xda50d57d8802553b00bb8e4d777bd5c4114086941119ca04edb15429f4818ed9",
|
||||||
"blockNumber": "0x1",
|
"blockNumber": "0x1",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0xa1410af902e98b32e0bbe464f8637ff464f1d4344b585127d2ce71f9cb39cb8a",
|
"blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f",
|
||||||
"blockNumber": "0x3",
|
"blockNumber": "0x3",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5e28",
|
"cumulativeGasUsed": "0x5e28",
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
"blockNumber": "0x3",
|
"blockNumber": "0x3",
|
||||||
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
|
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
|
||||||
"transactionIndex": "0x0",
|
"transactionIndex": "0x0",
|
||||||
"blockHash": "0xa1410af902e98b32e0bbe464f8637ff464f1d4344b585127d2ce71f9cb39cb8a",
|
"blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f",
|
||||||
"logIndex": "0x0",
|
"logIndex": "0x0",
|
||||||
"removed": false
|
"removed": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,11 +120,21 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
|
||||||
// Collect consensus-layer requests if Prague is enabled.
|
// Collect consensus-layer requests if Prague is enabled.
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
|
if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
|
||||||
|
// EIP-6110 deposits
|
||||||
depositRequests, err := core.ParseDepositLogs(allLogs, miner.chainConfig)
|
depositRequests, err := core.ParseDepositLogs(allLogs, miner.chainConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &newPayloadResult{err: err}
|
return &newPayloadResult{err: err}
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
requests = append(requests, depositRequests)
|
||||||
|
// create EVM for system calls
|
||||||
|
blockContext := core.NewEVMBlockContext(work.header, miner.chain, &work.header.Coinbase)
|
||||||
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, work.state, miner.chainConfig, vm.Config{})
|
||||||
|
// EIP-7002 withdrawals
|
||||||
|
withdrawalRequests := core.ProcessWithdrawalQueue(vmenv, work.state)
|
||||||
|
requests = append(requests, withdrawalRequests)
|
||||||
|
// EIP-7251 consolidations
|
||||||
|
consolidationRequests := core.ProcessConsolidationQueue(vmenv, work.state)
|
||||||
|
requests = append(requests, consolidationRequests)
|
||||||
}
|
}
|
||||||
if requests != nil {
|
if requests != nil {
|
||||||
reqHash := types.CalcRequestsHash(requests)
|
reqHash := types.CalcRequestsHash(requests)
|
||||||
|
|
|
@ -158,6 +158,7 @@ var (
|
||||||
GrayGlacierBlock: big.NewInt(0),
|
GrayGlacierBlock: big.NewInt(0),
|
||||||
ShanghaiTime: newUint64(0),
|
ShanghaiTime: newUint64(0),
|
||||||
CancunTime: newUint64(0),
|
CancunTime: newUint64(0),
|
||||||
|
PragueTime: newUint64(0),
|
||||||
TerminalTotalDifficulty: big.NewInt(0),
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
TerminalTotalDifficultyPassed: true,
|
TerminalTotalDifficultyPassed: true,
|
||||||
}
|
}
|
||||||
|
@ -244,7 +245,7 @@ var (
|
||||||
MergeNetsplitBlock: big.NewInt(0),
|
MergeNetsplitBlock: big.NewInt(0),
|
||||||
ShanghaiTime: newUint64(0),
|
ShanghaiTime: newUint64(0),
|
||||||
CancunTime: newUint64(0),
|
CancunTime: newUint64(0),
|
||||||
PragueTime: nil,
|
PragueTime: newUint64(0),
|
||||||
VerkleTime: nil,
|
VerkleTime: nil,
|
||||||
TerminalTotalDifficulty: big.NewInt(0),
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
TerminalTotalDifficultyPassed: true,
|
TerminalTotalDifficultyPassed: true,
|
||||||
|
|
|
@ -181,22 +181,32 @@ const (
|
||||||
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
|
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
|
||||||
var Bls12381MultiExpDiscountTable = [128]uint64{1200, 888, 764, 641, 594, 547, 500, 453, 438, 423, 408, 394, 379, 364, 349, 334, 330, 326, 322, 318, 314, 310, 306, 302, 298, 294, 289, 285, 281, 277, 273, 269, 268, 266, 265, 263, 262, 260, 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 241, 239, 238, 236, 235, 233, 232, 231, 229, 228, 226, 225, 223, 222, 221, 220, 219, 219, 218, 217, 216, 216, 215, 214, 213, 213, 212, 211, 211, 210, 209, 208, 208, 207, 206, 205, 205, 204, 203, 202, 202, 201, 200, 199, 199, 198, 197, 196, 196, 195, 194, 193, 193, 192, 191, 191, 190, 189, 188, 188, 187, 186, 185, 185, 184, 183, 182, 182, 181, 180, 179, 179, 178, 177, 176, 176, 175, 174}
|
var Bls12381MultiExpDiscountTable = [128]uint64{1200, 888, 764, 641, 594, 547, 500, 453, 438, 423, 408, 394, 379, 364, 349, 334, 330, 326, 322, 318, 314, 310, 306, 302, 298, 294, 289, 285, 281, 277, 273, 269, 268, 266, 265, 263, 262, 260, 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 241, 239, 238, 236, 235, 233, 232, 231, 229, 228, 226, 225, 223, 222, 221, 220, 219, 219, 218, 217, 216, 216, 215, 214, 213, 213, 212, 211, 211, 210, 209, 208, 208, 207, 206, 205, 205, 204, 203, 202, 202, 201, 200, 199, 199, 198, 197, 196, 196, 195, 194, 193, 193, 192, 191, 191, 190, 189, 188, 188, 187, 186, 185, 185, 184, 183, 182, 182, 181, 180, 179, 179, 178, 177, 176, 176, 175, 174}
|
||||||
|
|
||||||
|
// Difficulty parameters.
|
||||||
var (
|
var (
|
||||||
DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
|
DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
|
||||||
GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
|
GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
|
||||||
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
|
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
|
||||||
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
|
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
|
||||||
|
)
|
||||||
|
|
||||||
// BeaconRootsAddress is the address where historical beacon roots are stored as per EIP-4788
|
// System contracts.
|
||||||
BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02")
|
var (
|
||||||
|
|
||||||
// BeaconRootsCode is the code where historical beacon roots are stored as per EIP-4788
|
|
||||||
BeaconRootsCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500")
|
|
||||||
|
|
||||||
// SystemAddress is where the system-transaction is sent from as per EIP-4788
|
// SystemAddress is where the system-transaction is sent from as per EIP-4788
|
||||||
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
|
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
|
||||||
// HistoryStorageAddress is where the historical block hashes are stored.
|
|
||||||
|
// EIP-4788 - Beacon block root in the EVM
|
||||||
|
BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02")
|
||||||
|
BeaconRootsCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500")
|
||||||
|
|
||||||
|
// EIP-2935 - Serve historical block hashes from state
|
||||||
HistoryStorageAddress = common.HexToAddress("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e")
|
HistoryStorageAddress = common.HexToAddress("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e")
|
||||||
// HistoryStorageCode is the code with getters for historical block hashes.
|
|
||||||
HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500")
|
HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500")
|
||||||
|
|
||||||
|
// EIP-7002 - Execution layer triggerable withdrawals
|
||||||
|
WithdrawalQueueAddress = common.HexToAddress("0x09Fc772D0857550724b07B850a4323f39112aAaA")
|
||||||
|
WithdrawalQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460c7573615156028575f545f5260205ff35b36603814156101f05760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f057600182026001905f5b5f821115608057810190830284830290049160010191906065565b9093900434106101f057600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160db575060105b5f5b81811461017f5780604c02838201600302600401805490600101805490600101549160601b83528260140152807fffffffffffffffffffffffffffffffff0000000000000000000000000000000016826034015260401c906044018160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160dd565b9101809214610191579060025561019c565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101c957505f5b6001546002828201116101de5750505f6101e4565b01600290035b5f555f600155604c025ff35b5f5ffd")
|
||||||
|
|
||||||
|
// EIP-7251 - Increase the MAX_EFFECTIVE_BALANCE
|
||||||
|
ConsolidationQueueAddress = common.HexToAddress("0x01aBEa29659e5e97C95107F20bb753cD3e09bBBb")
|
||||||
|
ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460cf573615156028575f545f5260205ff35b366060141561019a5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f821115608057810190830284830290049160010191906065565b90939004341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060011160e3575060015b5f5b8181146101295780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160e5565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd")
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue