diff --git a/XDCx/token.go b/XDCx/token.go index 6596596930fa..dcee2ae36fbc 100644 --- a/XDCx/token.go +++ b/XDCx/token.go @@ -52,8 +52,9 @@ func (XDCx *XDCX) GetTokenDecimal(chain consensus.ChainContext, statedb *state.S return common.BasePrice, nil } var decimals uint8 + relayerSMC := statedb.RelayerRegistrationSMC() defer func() { - log.Debug("GetTokenDecimal from ", "relayerSMC", common.RelayerRegistrationSMC, "tokenAddr", tokenAddr.Hex(), "decimals", decimals) + log.Debug("GetTokenDecimal from ", "relayerSMC", relayerSMC, "tokenAddr", tokenAddr.Hex(), "decimals", decimals) }() contractABI, err := GetTokenAbi() if err != nil { diff --git a/XDCx/tradingstate/orderitem.go b/XDCx/tradingstate/orderitem.go index b87dfecfeca4..1ed13a863f6a 100644 --- a/XDCx/tradingstate/orderitem.go +++ b/XDCx/tradingstate/orderitem.go @@ -310,7 +310,7 @@ func IsValidRelayer(statedb *state.StateDB, address common.Address) bool { locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locRelayerState, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - balance := statedb.GetState(common.RelayerRegistrationSMC, locHashDeposit).Big() + balance := statedb.GetState(statedb.RelayerRegistrationSMC(), locHashDeposit).Big() if balance.Cmp(new(big.Int).Mul(common.BasePrice, common.RelayerLockedFund)) <= 0 { log.Debug("Relayer is not in relayer list", "relayer", address, "balance", balance) return false diff --git a/XDCx/tradingstate/relayer_state.go b/XDCx/tradingstate/relayer_state.go index 436ff2a5063e..a2426de8bee5 100644 --- a/XDCx/tradingstate/relayer_state.go +++ b/XDCx/tradingstate/relayer_state.go @@ -20,12 +20,16 @@ func GetLocMappingAtKey(key common.Hash, slot uint64) *big.Int { return ret } +func relayerRegistrationSMC(statedb *state.StateDB) common.Address { + return statedb.RelayerRegistrationSMC() +} + func GetExRelayerFee(relayer common.Address, statedb *state.StateDB) *big.Int { slot := RelayerMappingSlot["RELAYER_LIST"] locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_fee"]) locHash := common.BigToHash(locBig) - return statedb.GetState(common.RelayerRegistrationSMC, locHash).Big() + return statedb.GetState(relayerRegistrationSMC(statedb), locHash).Big() } func GetRelayerOwner(relayer common.Address, statedb *state.StateDB) common.Address { @@ -34,7 +38,7 @@ func GetRelayerOwner(relayer common.Address, statedb *state.StateDB) common.Addr log.Debug("GetRelayerOwner", "relayer", relayer.Hex(), "slot", slot, "locBig", locBig) locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_owner"]) locHash := common.BigToHash(locBig) - return common.BytesToAddress(statedb.GetState(common.RelayerRegistrationSMC, locHash).Bytes()) + return common.BytesToAddress(statedb.GetState(relayerRegistrationSMC(statedb), locHash).Bytes()) } // return true if relayer request to resign and have not withdraw locked fund @@ -42,7 +46,7 @@ func IsResignedRelayer(relayer common.Address, statedb *state.StateDB) bool { slot := RelayerMappingSlot["RESIGN_REQUESTS"] locBig := GetLocMappingAtKey(relayer.Hash(), slot) locHash := common.BigToHash(locBig) - return statedb.GetState(common.RelayerRegistrationSMC, locHash) != (common.Hash{}) + return statedb.GetState(relayerRegistrationSMC(statedb), locHash) != (common.Hash{}) } func GetBaseTokenLength(relayer common.Address, statedb *state.StateDB) uint64 { @@ -50,7 +54,7 @@ func GetBaseTokenLength(relayer common.Address, statedb *state.StateDB) uint64 { locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_fromTokens"]) locHash := common.BigToHash(locBig) - return statedb.GetState(common.RelayerRegistrationSMC, locHash).Big().Uint64() + return statedb.GetState(relayerRegistrationSMC(statedb), locHash).Big().Uint64() } func GetBaseTokenAtIndex(relayer common.Address, statedb *state.StateDB, index uint64) common.Address { @@ -59,7 +63,7 @@ func GetBaseTokenAtIndex(relayer common.Address, statedb *state.StateDB, index u locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_fromTokens"]) locHash := common.BigToHash(locBig) loc := state.GetLocDynamicArrAtElement(locHash, index, 1) - return common.BytesToAddress(statedb.GetState(common.RelayerRegistrationSMC, loc).Bytes()) + return common.BytesToAddress(statedb.GetState(relayerRegistrationSMC(statedb), loc).Bytes()) } func GetQuoteTokenLength(relayer common.Address, statedb *state.StateDB) uint64 { @@ -67,7 +71,7 @@ func GetQuoteTokenLength(relayer common.Address, statedb *state.StateDB) uint64 locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_toTokens"]) locHash := common.BigToHash(locBig) - return statedb.GetState(common.RelayerRegistrationSMC, locHash).Big().Uint64() + return statedb.GetState(relayerRegistrationSMC(statedb), locHash).Big().Uint64() } func GetQuoteTokenAtIndex(relayer common.Address, statedb *state.StateDB, index uint64) common.Address { @@ -76,13 +80,13 @@ func GetQuoteTokenAtIndex(relayer common.Address, statedb *state.StateDB, index locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_toTokens"]) locHash := common.BigToHash(locBig) loc := state.GetLocDynamicArrAtElement(locHash, index, 1) - return common.BytesToAddress(statedb.GetState(common.RelayerRegistrationSMC, loc).Bytes()) + return common.BytesToAddress(statedb.GetState(relayerRegistrationSMC(statedb), loc).Bytes()) } func GetRelayerCount(statedb *state.StateDB) uint64 { slot := RelayerMappingSlot["RelayerCount"] slotHash := common.BigToHash(new(big.Int).SetUint64(slot)) - valueHash := statedb.GetState(common.RelayerRegistrationSMC, slotHash) + valueHash := statedb.GetState(relayerRegistrationSMC(statedb), slotHash) return new(big.Int).SetBytes(valueHash.Bytes()).Uint64() } @@ -91,7 +95,7 @@ func GetAllCoinbases(statedb *state.StateDB) []common.Address { slot := RelayerMappingSlot["RELAYER_COINBASES"] coinbases := []common.Address{} for i := uint64(0); i < relayerCount; i++ { - valueHash := statedb.GetState(common.RelayerRegistrationSMC, common.BytesToHash(state.GetLocMappingAtKey(common.BigToHash(big.NewInt(int64(i))), slot).Bytes())) + valueHash := statedb.GetState(relayerRegistrationSMC(statedb), common.BytesToHash(state.GetLocMappingAtKey(common.BigToHash(big.NewInt(int64(i))), slot).Bytes())) coinbases = append(coinbases, common.BytesToAddress(valueHash.Bytes())) } return coinbases @@ -103,21 +107,21 @@ func GetAllTradingPairs(statedb *state.StateDB) (map[common.Hash]bool, error) { for _, coinbase := range coinbases { locBig := GetLocMappingAtKey(coinbase.Hash(), slot) fromTokenSlot := new(big.Int).Add(locBig, RelayerStructMappingSlot["_fromTokens"]) - fromTokenLength := statedb.GetState(common.RelayerRegistrationSMC, common.BigToHash(fromTokenSlot)).Big().Uint64() + fromTokenLength := statedb.GetState(relayerRegistrationSMC(statedb), common.BigToHash(fromTokenSlot)).Big().Uint64() toTokenSlot := new(big.Int).Add(locBig, RelayerStructMappingSlot["_toTokens"]) - toTokenLength := statedb.GetState(common.RelayerRegistrationSMC, common.BigToHash(toTokenSlot)).Big().Uint64() + toTokenLength := statedb.GetState(relayerRegistrationSMC(statedb), common.BigToHash(toTokenSlot)).Big().Uint64() if toTokenLength != fromTokenLength { return map[common.Hash]bool{}, fmt.Errorf("invalid length from token & to token: from :%d , to :%d ", fromTokenLength, toTokenLength) } fromTokens := []common.Address{} fromTokenSlotHash := common.BytesToHash(fromTokenSlot.Bytes()) for i := uint64(0); i < fromTokenLength; i++ { - fromToken := common.BytesToAddress(statedb.GetState(common.RelayerRegistrationSMC, state.GetLocDynamicArrAtElement(fromTokenSlotHash, i, uint64(1))).Bytes()) + fromToken := common.BytesToAddress(statedb.GetState(relayerRegistrationSMC(statedb), state.GetLocDynamicArrAtElement(fromTokenSlotHash, i, uint64(1))).Bytes()) fromTokens = append(fromTokens, fromToken) } toTokenSlotHash := common.BytesToHash(toTokenSlot.Bytes()) for i := uint64(0); i < toTokenLength; i++ { - toToken := common.BytesToAddress(statedb.GetState(common.RelayerRegistrationSMC, state.GetLocDynamicArrAtElement(toTokenSlotHash, i, uint64(1))).Bytes()) + toToken := common.BytesToAddress(statedb.GetState(relayerRegistrationSMC(statedb), state.GetLocDynamicArrAtElement(toTokenSlotHash, i, uint64(1))).Bytes()) log.Debug("GetAllTradingPairs all pair info", "from", fromTokens[i].Hex(), "toToken", toToken.Hex()) allPairs[GetTradingOrderBookHash(fromTokens[i], toToken)] = true @@ -133,14 +137,14 @@ func SubRelayerFee(relayer common.Address, fee *big.Int, statedb *state.StateDB) locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locBig, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - balance := statedb.GetState(common.RelayerRegistrationSMC, locHashDeposit).Big() + balance := statedb.GetState(relayerRegistrationSMC(statedb), locHashDeposit).Big() log.Debug("ApplyXDCXMatchedTransaction settle balance: SubRelayerFee BEFORE", "relayer", relayer, "balance", balance) if balance.Cmp(fee) < 0 { return errors.Errorf("relayer %s isn't enough XDC fee", relayer) } else { balance = new(big.Int).Sub(balance, fee) - statedb.SetState(common.RelayerRegistrationSMC, locHashDeposit, common.BigToHash(balance)) - statedb.SubBalance(common.RelayerRegistrationSMC, fee, tracing.BalanceChangeUnspecified) + statedb.SetState(relayerRegistrationSMC(statedb), locHashDeposit, common.BigToHash(balance)) + statedb.SubBalance(relayerRegistrationSMC(statedb), fee, tracing.BalanceChangeUnspecified) log.Debug("ApplyXDCXMatchedTransaction settle balance: SubRelayerFee AFTER", "relayer", relayer, "balance", balance) return nil } @@ -152,7 +156,7 @@ func CheckRelayerFee(relayer common.Address, fee *big.Int, statedb *state.StateD locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locBig, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - balance := statedb.GetState(common.RelayerRegistrationSMC, locHashDeposit).Big() + balance := statedb.GetState(relayerRegistrationSMC(statedb), locHashDeposit).Big() if new(big.Int).Sub(balance, fee).Cmp(new(big.Int).Mul(common.BasePrice, common.RelayerLockedFund)) < 0 { return errors.Errorf("relayer %s isn't enough XDC fee : balance %d , fee : %d ", relayer.Hex(), balance.Uint64(), fee.Uint64()) } @@ -296,7 +300,7 @@ func CheckSubRelayerFee(relayer common.Address, fee *big.Int, statedb *state.Sta locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locBig, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - balance = statedb.GetState(common.RelayerRegistrationSMC, locHashDeposit).Big() + balance = statedb.GetState(relayerRegistrationSMC(statedb), locHashDeposit).Big() } log.Debug("CheckSubRelayerFee settle balance: SubRelayerFee ", "relayer", relayer, "balance", balance, "fee", fee) if balance.Cmp(fee) < 0 { @@ -344,6 +348,6 @@ func SetSubRelayerFee(relayer common.Address, balance *big.Int, fee *big.Int, st locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locBig, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - statedb.SetState(common.RelayerRegistrationSMC, locHashDeposit, common.BigToHash(balance)) - statedb.SubBalance(common.RelayerRegistrationSMC, fee, tracing.BalanceChangeUnspecified) + statedb.SetState(relayerRegistrationSMC(statedb), locHashDeposit, common.BigToHash(balance)) + statedb.SubBalance(relayerRegistrationSMC(statedb), fee, tracing.BalanceChangeUnspecified) } diff --git a/XDCxlending/lendingstate/lendingcontract.go b/XDCxlending/lendingstate/lendingcontract.go index 3e533d886b87..2381b690182a 100644 --- a/XDCxlending/lendingstate/lendingcontract.go +++ b/XDCxlending/lendingstate/lendingcontract.go @@ -36,6 +36,10 @@ var ( } ) +func lendingRegistrationSMC(statedb *state.StateDB) common.Address { + return statedb.LendingRegistrationSMC() +} + // @function IsValidRelayer : return whether the given address is the coinbase of a valid relayer or not // @param statedb : current state // @param coinbase: coinbase address of relayer @@ -45,7 +49,7 @@ func IsValidRelayer(statedb *state.StateDB, coinbase common.Address) bool { // a valid relayer must have baseToken locBaseToken := state.GetLocOfStructElement(locRelayerState, LendingRelayerStructSlots["bases"]) - if v := statedb.GetState(common.LendingRegistrationSMC, common.BytesToHash(locBaseToken.Bytes())); v != (common.Hash{}) { + if v := statedb.GetState(lendingRegistrationSMC(statedb), common.BytesToHash(locBaseToken.Bytes())); v != (common.Hash{}) { if tradingstate.IsResignedRelayer(coinbase, statedb) { return false } @@ -54,7 +58,7 @@ func IsValidRelayer(statedb *state.StateDB, coinbase common.Address) bool { locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locRelayerStateTrading, tradingstate.RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - balance := statedb.GetState(common.RelayerRegistrationSMC, locHashDeposit).Big() + balance := statedb.GetState(statedb.RelayerRegistrationSMC(), locHashDeposit).Big() expectedFund := new(big.Int).Mul(common.BasePrice, common.RelayerLockedFund) if balance.Cmp(expectedFund) <= 0 { log.Debug("Relayer is not in relayer list", "relayer", coinbase, "balance", balance, "expected", expectedFund) @@ -72,7 +76,7 @@ func IsValidRelayer(statedb *state.StateDB, coinbase common.Address) bool { func GetFee(statedb *state.StateDB, coinbase common.Address) *big.Int { locRelayerState := state.GetLocMappingAtKey(coinbase.Hash(), LendingRelayerListSlot) locHash := common.BytesToHash(new(big.Int).Add(locRelayerState, LendingRelayerStructSlots["fee"]).Bytes()) - return statedb.GetState(common.LendingRegistrationSMC, locHash).Big() + return statedb.GetState(lendingRegistrationSMC(statedb), locHash).Big() } // @function GetBaseList @@ -83,10 +87,10 @@ func GetBaseList(statedb *state.StateDB, coinbase common.Address) []common.Addre baseList := []common.Address{} locRelayerState := state.GetLocMappingAtKey(coinbase.Hash(), LendingRelayerListSlot) locBaseHash := state.GetLocOfStructElement(locRelayerState, LendingRelayerStructSlots["bases"]) - length := statedb.GetState(common.LendingRegistrationSMC, locBaseHash).Big().Uint64() + length := statedb.GetState(lendingRegistrationSMC(statedb), locBaseHash).Big().Uint64() for i := uint64(0); i < length; i++ { loc := state.GetLocDynamicArrAtElement(locBaseHash, i, 1) - addr := common.BytesToAddress(statedb.GetState(common.LendingRegistrationSMC, loc).Bytes()) + addr := common.BytesToAddress(statedb.GetState(lendingRegistrationSMC(statedb), loc).Bytes()) if addr != (common.Address{}) { baseList = append(baseList, addr) } @@ -102,10 +106,10 @@ func GetTerms(statedb *state.StateDB, coinbase common.Address) []uint64 { terms := []uint64{} locRelayerState := state.GetLocMappingAtKey(coinbase.Hash(), LendingRelayerListSlot) locTermHash := state.GetLocOfStructElement(locRelayerState, LendingRelayerStructSlots["terms"]) - length := statedb.GetState(common.LendingRegistrationSMC, locTermHash).Big().Uint64() + length := statedb.GetState(lendingRegistrationSMC(statedb), locTermHash).Big().Uint64() for i := uint64(0); i < length; i++ { loc := state.GetLocDynamicArrAtElement(locTermHash, i, 1) - t := statedb.GetState(common.LendingRegistrationSMC, loc).Big().Uint64() + t := statedb.GetState(lendingRegistrationSMC(statedb), loc).Big().Uint64() if t != uint64(0) { terms = append(terms, t) } @@ -163,10 +167,10 @@ func GetCollaterals(statedb *state.StateDB, coinbase common.Address, baseToken c // if collaterals is not defined for the relayer, return default collaterals locDefaultCollateralHash := state.GetLocSimpleVariable(DefaultCollateralSlot) - length := statedb.GetState(common.LendingRegistrationSMC, locDefaultCollateralHash).Big().Uint64() + length := statedb.GetState(lendingRegistrationSMC(statedb), locDefaultCollateralHash).Big().Uint64() for i := uint64(0); i < length; i++ { loc := state.GetLocDynamicArrAtElement(locDefaultCollateralHash, i, 1) - addr := common.BytesToAddress(statedb.GetState(common.LendingRegistrationSMC, loc).Bytes()) + addr := common.BytesToAddress(statedb.GetState(lendingRegistrationSMC(statedb), loc).Bytes()) if addr != (common.Address{}) { collaterals = append(collaterals, addr) } @@ -183,9 +187,9 @@ func GetCollateralDetail(statedb *state.StateDB, token common.Address) (depositR locDepositRate := state.GetLocOfStructElement(collateralState, CollateralStructSlots["depositRate"]) locLiquidationRate := state.GetLocOfStructElement(collateralState, CollateralStructSlots["liquidationRate"]) locRecallRate := state.GetLocOfStructElement(collateralState, CollateralStructSlots["recallRate"]) - depositRate = statedb.GetState(common.LendingRegistrationSMC, locDepositRate).Big() - liquidationRate = statedb.GetState(common.LendingRegistrationSMC, locLiquidationRate).Big() - recallRate = statedb.GetState(common.LendingRegistrationSMC, locRecallRate).Big() + depositRate = statedb.GetState(lendingRegistrationSMC(statedb), locDepositRate).Big() + liquidationRate = statedb.GetState(lendingRegistrationSMC(statedb), locLiquidationRate).Big() + recallRate = statedb.GetState(lendingRegistrationSMC(statedb), locRecallRate).Big() return depositRate, liquidationRate, recallRate } @@ -197,8 +201,8 @@ func GetCollateralPrice(statedb *state.StateDB, collateralToken common.Address, locCollateralPrice := common.BigToHash(new(big.Int).Add(new(big.Int).SetBytes(locLendingTokenPriceByte), PriceStructSlots["price"])) locBlockNumber := common.BigToHash(new(big.Int).Add(new(big.Int).SetBytes(locLendingTokenPriceByte), PriceStructSlots["blockNumber"])) - price = statedb.GetState(common.LendingRegistrationSMC, locCollateralPrice).Big() - blockNumber = statedb.GetState(common.LendingRegistrationSMC, locBlockNumber).Big() + price = statedb.GetState(lendingRegistrationSMC(statedb), locCollateralPrice).Big() + blockNumber = statedb.GetState(lendingRegistrationSMC(statedb), locBlockNumber).Big() return price, blockNumber } @@ -208,10 +212,10 @@ func GetCollateralPrice(statedb *state.StateDB, collateralToken common.Address, func GetSupportedTerms(statedb *state.StateDB) []uint64 { terms := []uint64{} locSupportedTerm := state.GetLocSimpleVariable(SupportedTermSlot) - length := statedb.GetState(common.LendingRegistrationSMC, locSupportedTerm).Big().Uint64() + length := statedb.GetState(lendingRegistrationSMC(statedb), locSupportedTerm).Big().Uint64() for i := uint64(0); i < length; i++ { loc := state.GetLocDynamicArrAtElement(locSupportedTerm, i, 1) - t := statedb.GetState(common.LendingRegistrationSMC, loc).Big().Uint64() + t := statedb.GetState(lendingRegistrationSMC(statedb), loc).Big().Uint64() if t != 0 { terms = append(terms, t) } @@ -225,10 +229,10 @@ func GetSupportedTerms(statedb *state.StateDB) []uint64 { func GetSupportedBaseToken(statedb *state.StateDB) []common.Address { baseTokens := []common.Address{} locSupportedBaseToken := state.GetLocSimpleVariable(SupportedBaseSlot) - length := statedb.GetState(common.LendingRegistrationSMC, locSupportedBaseToken).Big().Uint64() + length := statedb.GetState(lendingRegistrationSMC(statedb), locSupportedBaseToken).Big().Uint64() for i := uint64(0); i < length; i++ { loc := state.GetLocDynamicArrAtElement(locSupportedBaseToken, i, 1) - addr := common.BytesToAddress(statedb.GetState(common.LendingRegistrationSMC, loc).Bytes()) + addr := common.BytesToAddress(statedb.GetState(lendingRegistrationSMC(statedb), loc).Bytes()) if addr != (common.Address{}) { baseTokens = append(baseTokens, addr) } @@ -254,10 +258,10 @@ func GetAllCollateral(statedb *state.StateDB) []common.Address { //} locDefaultCollateralHash := state.GetLocSimpleVariable(DefaultCollateralSlot) - length := statedb.GetState(common.LendingRegistrationSMC, locDefaultCollateralHash).Big().Uint64() + length := statedb.GetState(lendingRegistrationSMC(statedb), locDefaultCollateralHash).Big().Uint64() for i := uint64(0); i < length; i++ { loc := state.GetLocDynamicArrAtElement(locDefaultCollateralHash, i, 1) - addr := common.BytesToAddress(statedb.GetState(common.LendingRegistrationSMC, loc).Bytes()) + addr := common.BytesToAddress(statedb.GetState(lendingRegistrationSMC(statedb), loc).Bytes()) if addr != (common.Address{}) { collaterals = append(collaterals, addr) } diff --git a/XDCxlending/lendingstate/lendingitem_test.go b/XDCxlending/lendingstate/lendingitem_test.go index 9aefdb9a1dcf..0d75d72b4641 100644 --- a/XDCxlending/lendingstate/lendingitem_test.go +++ b/XDCxlending/lendingstate/lendingitem_test.go @@ -13,6 +13,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto/keccak" + "github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/rpc" ) @@ -159,7 +160,7 @@ func TestLendingItem_VerifyLendingStatus(t *testing.T) { func SetFee(statedb *state.StateDB, coinbase common.Address, feeRate *big.Int) { locRelayerState := state.GetLocMappingAtKey(coinbase.Hash(), LendingRelayerListSlot) locHash := common.BytesToHash(new(big.Int).Add(locRelayerState, LendingRelayerStructSlots["fee"]).Bytes()) - statedb.SetState(common.LendingRegistrationSMC, locHash, common.BigToHash(feeRate)) + statedb.SetState(statedb.LendingRegistrationSMC(), locHash, common.BigToHash(feeRate)) } func SetCollateralDetail(statedb *state.StateDB, token common.Address, depositRate *big.Int, liquidationRate *big.Int, price *big.Int) { @@ -167,14 +168,15 @@ func SetCollateralDetail(statedb *state.StateDB, token common.Address, depositRa locDepositRate := state.GetLocOfStructElement(collateralState, CollateralStructSlots["depositRate"]) locLiquidationRate := state.GetLocOfStructElement(collateralState, CollateralStructSlots["liquidationRate"]) locCollateralPrice := state.GetLocOfStructElement(collateralState, CollateralStructSlots["price"]) - statedb.SetState(common.LendingRegistrationSMC, locDepositRate, common.BigToHash(depositRate)) - statedb.SetState(common.LendingRegistrationSMC, locLiquidationRate, common.BigToHash(liquidationRate)) - statedb.SetState(common.LendingRegistrationSMC, locCollateralPrice, common.BigToHash(price)) + statedb.SetState(statedb.LendingRegistrationSMC(), locDepositRate, common.BigToHash(depositRate)) + statedb.SetState(statedb.LendingRegistrationSMC(), locLiquidationRate, common.BigToHash(liquidationRate)) + statedb.SetState(statedb.LendingRegistrationSMC(), locCollateralPrice, common.BigToHash(price)) } func TestVerifyBalance(t *testing.T) { db := rawdb.NewMemoryDatabase() statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(db)) + statedb.SetChainConfig(params.LocalnetChainConfig) relayer := common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e") uAddr := common.HexToAddress("0xDeE6238780f98c0ca2c2C28453149bEA49a3Abc9") lendingToken := common.HexToAddress("0xd9bb01454c85247B2ef35BB5BE57384cC275a8cf") // USD diff --git a/XDCxlending/lendingstate/relayer.go b/XDCxlending/lendingstate/relayer.go index 829a759c17fe..fe1035313302 100644 --- a/XDCxlending/lendingstate/relayer.go +++ b/XDCxlending/lendingstate/relayer.go @@ -20,12 +20,16 @@ func GetLocMappingAtKey(key common.Hash, slot uint64) *big.Int { return ret } +func relayerRegistrationSMC(statedb *state.StateDB) common.Address { + return statedb.RelayerRegistrationSMC() +} + func GetExRelayerFee(relayer common.Address, statedb *state.StateDB) *big.Int { slot := RelayerMappingSlot["RELAYER_LIST"] locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_fee"]) locHash := common.BigToHash(locBig) - return statedb.GetState(common.RelayerRegistrationSMC, locHash).Big() + return statedb.GetState(relayerRegistrationSMC(statedb), locHash).Big() } func GetRelayerOwner(relayer common.Address, statedb *state.StateDB) common.Address { @@ -34,7 +38,7 @@ func GetRelayerOwner(relayer common.Address, statedb *state.StateDB) common.Addr log.Debug("GetRelayerOwner", "relayer", relayer.Hex(), "slot", slot, "locBig", locBig) locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_owner"]) locHash := common.BigToHash(locBig) - return common.BytesToAddress(statedb.GetState(common.RelayerRegistrationSMC, locHash).Bytes()) + return common.BytesToAddress(statedb.GetState(relayerRegistrationSMC(statedb), locHash).Bytes()) } // return true if relayer request to resign and have not withdraw locked fund @@ -42,7 +46,7 @@ func IsResignedRelayer(relayer common.Address, statedb *state.StateDB) bool { slot := RelayerMappingSlot["RESIGN_REQUESTS"] locBig := GetLocMappingAtKey(relayer.Hash(), slot) locHash := common.BigToHash(locBig) - return statedb.GetState(common.RelayerRegistrationSMC, locHash) != (common.Hash{}) + return statedb.GetState(relayerRegistrationSMC(statedb), locHash) != (common.Hash{}) } func GetBaseTokenLength(relayer common.Address, statedb *state.StateDB) uint64 { @@ -50,7 +54,7 @@ func GetBaseTokenLength(relayer common.Address, statedb *state.StateDB) uint64 { locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_fromTokens"]) locHash := common.BigToHash(locBig) - return statedb.GetState(common.RelayerRegistrationSMC, locHash).Big().Uint64() + return statedb.GetState(relayerRegistrationSMC(statedb), locHash).Big().Uint64() } func GetBaseTokenAtIndex(relayer common.Address, statedb *state.StateDB, index uint64) common.Address { @@ -59,7 +63,7 @@ func GetBaseTokenAtIndex(relayer common.Address, statedb *state.StateDB, index u locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_fromTokens"]) locHash := common.BigToHash(locBig) loc := state.GetLocDynamicArrAtElement(locHash, index, 1) - return common.BytesToAddress(statedb.GetState(common.RelayerRegistrationSMC, loc).Bytes()) + return common.BytesToAddress(statedb.GetState(relayerRegistrationSMC(statedb), loc).Bytes()) } func GetQuoteTokenLength(relayer common.Address, statedb *state.StateDB) uint64 { @@ -67,7 +71,7 @@ func GetQuoteTokenLength(relayer common.Address, statedb *state.StateDB) uint64 locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_toTokens"]) locHash := common.BigToHash(locBig) - return statedb.GetState(common.RelayerRegistrationSMC, locHash).Big().Uint64() + return statedb.GetState(relayerRegistrationSMC(statedb), locHash).Big().Uint64() } func GetQuoteTokenAtIndex(relayer common.Address, statedb *state.StateDB, index uint64) common.Address { @@ -76,7 +80,7 @@ func GetQuoteTokenAtIndex(relayer common.Address, statedb *state.StateDB, index locBig = new(big.Int).Add(locBig, RelayerStructMappingSlot["_toTokens"]) locHash := common.BigToHash(locBig) loc := state.GetLocDynamicArrAtElement(locHash, index, 1) - return common.BytesToAddress(statedb.GetState(common.RelayerRegistrationSMC, loc).Bytes()) + return common.BytesToAddress(statedb.GetState(relayerRegistrationSMC(statedb), loc).Bytes()) } func SubRelayerFee(relayer common.Address, fee *big.Int, statedb *state.StateDB) error { @@ -85,14 +89,14 @@ func SubRelayerFee(relayer common.Address, fee *big.Int, statedb *state.StateDB) locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locBig, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - balance := statedb.GetState(common.RelayerRegistrationSMC, locHashDeposit).Big() + balance := statedb.GetState(relayerRegistrationSMC(statedb), locHashDeposit).Big() log.Debug("ApplyXDCXMatchedTransaction settle balance: SubRelayerFee BEFORE", "relayer", relayer, "balance", balance) if balance.Cmp(fee) < 0 { return errors.Errorf("relayer %s isn't enough XDC fee", relayer) } else { balance = new(big.Int).Sub(balance, fee) - statedb.SetState(common.RelayerRegistrationSMC, locHashDeposit, common.BigToHash(balance)) - statedb.SubBalance(common.RelayerRegistrationSMC, fee, tracing.BalanceChangeUnspecified) + statedb.SetState(relayerRegistrationSMC(statedb), locHashDeposit, common.BigToHash(balance)) + statedb.SubBalance(relayerRegistrationSMC(statedb), fee, tracing.BalanceChangeUnspecified) log.Debug("ApplyXDCXMatchedTransaction settle balance: SubRelayerFee AFTER", "relayer", relayer, "balance", balance) return nil } @@ -104,7 +108,7 @@ func CheckRelayerFee(relayer common.Address, fee *big.Int, statedb *state.StateD locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locBig, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - balance := statedb.GetState(common.RelayerRegistrationSMC, locHashDeposit).Big() + balance := statedb.GetState(relayerRegistrationSMC(statedb), locHashDeposit).Big() if new(big.Int).Sub(balance, fee).Cmp(new(big.Int).Mul(common.BasePrice, common.RelayerLockedFund)) < 0 { return errors.Errorf("relayer %s isn't enough XDC fee : balance %d , fee : %d ", relayer.Hex(), balance.Uint64(), fee.Uint64()) } @@ -249,7 +253,7 @@ func CheckSubRelayerFee(relayer common.Address, fee *big.Int, statedb *state.Sta locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locBig, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - balance = statedb.GetState(common.RelayerRegistrationSMC, locHashDeposit).Big() + balance = statedb.GetState(relayerRegistrationSMC(statedb), locHashDeposit).Big() } log.Debug("CheckSubRelayerFee settle balance: SubRelayerFee ", "relayer", relayer, "balance", balance, "fee", fee) if balance.Cmp(fee) < 0 { @@ -297,6 +301,6 @@ func SetSubRelayerFee(relayer common.Address, balance *big.Int, fee *big.Int, st locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBigDeposit := new(big.Int).SetUint64(uint64(0)).Add(locBig, RelayerStructMappingSlot["_deposit"]) locHashDeposit := common.BigToHash(locBigDeposit) - statedb.SetState(common.RelayerRegistrationSMC, locHashDeposit, common.BigToHash(balance)) - statedb.SubBalance(common.RelayerRegistrationSMC, fee, tracing.BalanceChangeUnspecified) + statedb.SetState(relayerRegistrationSMC(statedb), locHashDeposit, common.BigToHash(balance)) + statedb.SubBalance(relayerRegistrationSMC(statedb), fee, tracing.BalanceChangeUnspecified) } diff --git a/accounts/abi/abigen/bind_test.go b/accounts/abi/abigen/bind_test.go index 19deeae42974..44d98a9bef93 100644 --- a/accounts/abi/abigen/bind_test.go +++ b/accounts/abi/abigen/bind_test.go @@ -298,7 +298,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy an interaction tester contract and call a transaction on it @@ -355,7 +355,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy a tuple tester contract and execute a structured call on it @@ -402,7 +402,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy a tuple tester contract and execute a structured call on it @@ -461,7 +461,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy a slice tester contract and execute a n array call on it @@ -512,7 +512,7 @@ var bindTests = []struct { config := *params.TestXDPoSMockChainConfig config.Eip1559Block = big.NewInt(0) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, &config) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, &config) defer sim.Close() // Deploy a default method invoker contract and execute its default method @@ -580,7 +580,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy a structs method invoker contract and execute its default method @@ -713,7 +713,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy a funky gas pattern contract @@ -765,7 +765,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy a sender tester contract and execute a structured call on it @@ -841,7 +841,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy a underscorer tester contract and execute a structured call on it @@ -936,7 +936,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy an eventer contract @@ -1128,7 +1128,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() //deploy the test contract @@ -1266,7 +1266,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() _, _, contract, err := DeployTuple(auth, sim) @@ -1406,7 +1406,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // deploy the test contract @@ -1497,7 +1497,7 @@ var bindTests = []struct { addr := crypto.PubkeyToAddress(key.PublicKey) // Deploy registrar contract - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) @@ -1560,7 +1560,7 @@ var bindTests = []struct { addr := crypto.PubkeyToAddress(key.PublicKey) // Deploy registrar contract - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) @@ -1623,7 +1623,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() // Deploy a tester contract and execute a structured call on it @@ -1684,7 +1684,7 @@ var bindTests = []struct { key, _ := crypto.GenerateKey() addr := crypto.PubkeyToAddress(key.PublicKey) - sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) + sim := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) defer sim.Close() opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) diff --git a/accounts/abi/bind/v2/util_test.go b/accounts/abi/bind/v2/util_test.go index 07d246c806da..03f30eba950b 100644 --- a/accounts/abi/bind/v2/util_test.go +++ b/accounts/abi/bind/v2/util_test.go @@ -56,7 +56,6 @@ var waitDeployedTests = map[string]struct { func TestWaitDeployed(t *testing.T) { t.Parallel() config := *params.TestXDPoSMockChainConfig - config.Eip1559Block = big.NewInt(0) for name, test := range waitDeployedTests { backend := simulated.New( types.GenesisAlloc{ @@ -108,7 +107,6 @@ func TestWaitDeployed(t *testing.T) { func TestWaitDeployedCornerCases(t *testing.T) { config := *params.TestXDPoSMockChainConfig - config.Eip1559Block = big.NewInt(0) var ( backend = backends.NewXDCSimulatedBackend( types.GenesisAlloc{ diff --git a/cmd/XDC/chaincmd.go b/cmd/XDC/chaincmd.go index a4a45c40ba72..2a0612076919 100644 --- a/cmd/XDC/chaincmd.go +++ b/cmd/XDC/chaincmd.go @@ -187,8 +187,7 @@ func initGenesis(ctx *cli.Context) error { if err != nil { utils.Fatalf("invalid genesis json: %v", err) } - - if genesis.Config.ChainID != nil { + if genesis.Config != nil && genesis.Config.ChainID != nil { common.CopyConstants(genesis.Config.ChainID.Uint64()) } @@ -201,10 +200,13 @@ func initGenesis(ctx *cli.Context) error { if err != nil { utils.Fatalf("Failed to open database: %v", err) } - _, hash, err := core.SetupGenesisBlock(chaindb, genesis) + _, hash, compatErr, err := core.SetupGenesisBlock(chaindb, genesis) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } + if compatErr != nil { + utils.Fatalf("Failed to write chain config: %v", compatErr) + } chaindb.Close() log.Info("Successfully wrote genesis state", "database", name, "hash", hash) return nil diff --git a/cmd/XDC/dao_test.go b/cmd/XDC/dao_test.go index e46398b6404c..37e6b5ee9da6 100644 --- a/cmd/XDC/dao_test.go +++ b/cmd/XDC/dao_test.go @@ -31,13 +31,19 @@ var daoOldGenesis = `{ "alloc" : {}, "coinbase" : "0x0000000000000000000000000000000000000000", "difficulty" : "0x20000", - "extraData" : "", + "extraData" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit" : "0x2fefd8", "nonce" : "0x0000000000000042", "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp" : "0x00", - "config" : {} + "config" : { + "chainId" : 1337, + "tipTRC21FeeBlock" : 0, + "XDPoS": { + "maxMasternodesV2": 108 + } + } }` // Genesis block for nodes which actively oppose the DAO fork @@ -45,15 +51,20 @@ var daoNoForkGenesis = `{ "alloc" : {}, "coinbase" : "0x0000000000000000000000000000000000000000", "difficulty" : "0x20000", - "extraData" : "", + "extraData" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit" : "0x2fefd8", "nonce" : "0x0000000000000042", "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp" : "0x00", "config" : { + "chainId" : 1337, + "tipTRC21FeeBlock" : 0, "daoForkBlock" : 314, - "daoForkSupport" : false + "daoForkSupport" : false, + "XDPoS": { + "maxMasternodesV2": 108 + } } }` @@ -62,19 +73,23 @@ var daoProForkGenesis = `{ "alloc" : {}, "coinbase" : "0x0000000000000000000000000000000000000000", "difficulty" : "0x20000", - "extraData" : "", + "extraData" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit" : "0x2fefd8", "nonce" : "0x0000000000000042", "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp" : "0x00", "config" : { + "chainId" : 1337, + "tipTRC21FeeBlock" : 0, "daoForkBlock" : 314, - "daoForkSupport" : true + "daoForkSupport" : true, + "XDPoS": { + "maxMasternodesV2": 108 + } } }` -var daoGenesisHash = common.HexToHash("29a4b5d743bfbda3a7461974d49c62bf23ba5df9c8b01de8256e2ac2a9ae1cd8") var daoGenesisForkBlock = big.NewInt(314) // TestDAOForkBlockNewChain tests that the DAO hard-fork number and the nodes support/opposition is correctly @@ -122,9 +137,10 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc } defer db.Close() - genesisHash := common.HexToHash("8d13370621558f4ed0da587934473c0404729f28b0ff1d50e5fdd840457a2f17") - if genesis != "" { - genesisHash = daoGenesisHash + genesisHash := rawdb.ReadCanonicalHash(db, 0) + if genesisHash == (common.Hash{}) { + t.Errorf("test %d: failed to read canonical genesis hash", test) + return } config, err := rawdb.ReadChainConfig(db, genesisHash) if err != nil { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 1928060037af..8eeef3b0d2fc 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1595,18 +1595,18 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { switch { case ctx.Bool(MainnetFlag.Name): if !ctx.IsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 50 + cfg.NetworkId = params.XDCMainnetChainConfig.ChainID.Uint64() // 50 } cfg.Genesis = core.DefaultGenesisBlock() case ctx.Bool(TestnetFlag.Name): common.IsTestnet = true if !ctx.IsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 51 + cfg.NetworkId = params.TestnetChainConfig.ChainID.Uint64() // 51 } cfg.Genesis = core.DefaultTestnetGenesisBlock() case ctx.Bool(DevnetFlag.Name): if !ctx.IsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 5551 + cfg.NetworkId = params.DevnetChainConfig.ChainID.Uint64() // 5551 } cfg.Genesis = core.DefaultDevnetGenesisBlock() case ctx.Bool(DeveloperFlag.Name): @@ -1676,12 +1676,12 @@ func SetNetworkFlagById(ctx *cli.Context, cfg *ethconfig.Config) { if ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = ctx.Uint64(NetworkIdFlag.Name) switch cfg.NetworkId { - case 50: + case params.XDCMainnetChainConfig.ChainID.Uint64(): // 50 ctx.Set(MainnetFlag.Name, "true") - case 51: + case params.TestnetChainConfig.ChainID.Uint64(): // 51 common.IsTestnet = true ctx.Set(TestnetFlag.Name, "true") - case 5551: + case params.DevnetChainConfig.ChainID.Uint64(): // 5551 ctx.Set(DevnetFlag.Name, "true") } } diff --git a/common/bigint.go b/common/bigint.go new file mode 100644 index 000000000000..6ebab82ec750 --- /dev/null +++ b/common/bigint.go @@ -0,0 +1,11 @@ +package common + +import "math/big" + +// CloneBigInt returns a deep copy of value. It returns nil if value is nil. +func CloneBigInt(value *big.Int) *big.Int { + if value == nil { + return nil + } + return new(big.Int).Set(value) +} diff --git a/common/constants.all.go b/common/constants.all.go index f84028eefbd7..289c73ea88a7 100644 --- a/common/constants.all.go +++ b/common/constants.all.go @@ -41,40 +41,7 @@ var ( ) type constant struct { - chainID uint64 - denylistHFNumber uint64 - maxMasternodesV2 int // Last v1 masternodes - - tip2019Block *big.Int - tipSigning *big.Int - tipRandomize *big.Int - tipNoHalvingMNReward *big.Int // hard fork no halving masternodes reward - tipXDCX *big.Int - tipXDCXLending *big.Int - tipXDCXCancellationFee *big.Int - tipTRC21Fee *big.Int - tipIncreaseMasternodes *big.Int // Upgrade MN Count at Block. - berlinBlock *big.Int - londonBlock *big.Int - mergeBlock *big.Int - shanghaiBlock *big.Int - blockNumberGas50x *big.Int - TIPV2SwitchBlock *big.Int - tipXDCXMinerDisable *big.Int - tipXDCXReceiverDisable *big.Int - tipUpgradeReward *big.Int - tipUpgradePenalty *big.Int - tipEpochHalving *big.Int - eip1559Block *big.Int - cancunBlock *big.Int - pragueBlock *big.Int - osakaBlock *big.Int - dynamicGasLimitBlock *big.Int - - trc21IssuerSMC Address - xdcxListingSMC Address - relayerRegistrationSMC Address - lendingRegistrationSMC Address + chainID uint64 ignoreSignerCheckBlockArray map[uint64]struct{} @@ -83,76 +50,12 @@ type constant struct { func (c *constant) print() { fmt.Println("chainID:", c.chainID) - fmt.Println("denylistHFNumber:", c.denylistHFNumber) - fmt.Println("maxMasternodesV2:", c.maxMasternodesV2) - fmt.Println("tip2019Block:", c.tip2019Block) - fmt.Println("tipSigning:", c.tipSigning) - fmt.Println("tipRandomize:", c.tipRandomize) - fmt.Println("tipNoHalvingMNReward:", c.tipNoHalvingMNReward) - fmt.Println("tipXDCX:", c.tipXDCX) - fmt.Println("tipXDCXLending:", c.tipXDCXLending) - fmt.Println("tipXDCXCancellationFee:", c.tipXDCXCancellationFee) - fmt.Println("tipTRC21Fee:", c.tipTRC21Fee) - fmt.Println("tipIncreaseMasternodes:", c.tipIncreaseMasternodes) - fmt.Println("berlinBlock:", c.berlinBlock) - fmt.Println("londonBlock:", c.londonBlock) - fmt.Println("mergeBlock:", c.mergeBlock) - fmt.Println("shanghaiBlock:", c.shanghaiBlock) - fmt.Println("blockNumberGas50x:", c.blockNumberGas50x) - fmt.Println("TIPV2SwitchBlock:", c.TIPV2SwitchBlock) - fmt.Println("tipXDCXMinerDisable:", c.tipXDCXMinerDisable) - fmt.Println("tipXDCXReceiverDisable:", c.tipXDCXReceiverDisable) - fmt.Println("tipUpgradeReward:", c.tipUpgradeReward) - fmt.Println("tipUpgradePenalty:", c.tipUpgradePenalty) - fmt.Println("tipEpochHalving:", c.tipEpochHalving) - fmt.Println("eip1559Block:", c.eip1559Block) - fmt.Println("cancunBlock:", c.cancunBlock) - fmt.Println("pragueBlock:", c.pragueBlock) - fmt.Println("osakaBlock:", c.osakaBlock) - fmt.Println("dynamicGasLimitBlock:", c.dynamicGasLimitBlock) - fmt.Println("trc21IssuerSMC:", c.trc21IssuerSMC) - fmt.Println("xdcxListingSMC:", c.xdcxListingSMC) - fmt.Println("relayerRegistrationSMC:", c.relayerRegistrationSMC) - fmt.Println("lendingRegistrationSMC:", c.lendingRegistrationSMC) fmt.Println("ignoreSignerCheckBlockArray:", c.ignoreSignerCheckBlockArray) fmt.Println("denylist:", c.denylist) } // variables for specific networks, copy values from mainnet constant to pass tests var ( - DenylistHFNumber = MainnetConstant.denylistHFNumber - MaxMasternodesV2 = MainnetConstant.maxMasternodesV2 // Last v1 masternodes - - TIP2019Block = MainnetConstant.tip2019Block - TIPSigning = MainnetConstant.tipSigning - TIPRandomize = MainnetConstant.tipRandomize - TIPNoHalvingMNReward = MainnetConstant.tipNoHalvingMNReward - TIPXDCX = MainnetConstant.tipXDCX - TIPXDCXLending = MainnetConstant.tipXDCXLending - TIPXDCXCancellationFee = MainnetConstant.tipXDCXCancellationFee - TIPTRC21Fee = MainnetConstant.tipTRC21Fee - TIPIncreaseMasternodes = MainnetConstant.tipIncreaseMasternodes - BerlinBlock = MainnetConstant.berlinBlock - LondonBlock = MainnetConstant.londonBlock - MergeBlock = MainnetConstant.mergeBlock - ShanghaiBlock = MainnetConstant.shanghaiBlock - BlockNumberGas50x = MainnetConstant.blockNumberGas50x - TIPXDCXMinerDisable = MainnetConstant.tipXDCXMinerDisable - TIPXDCXReceiverDisable = MainnetConstant.tipXDCXReceiverDisable - Eip1559Block = MainnetConstant.eip1559Block - CancunBlock = MainnetConstant.cancunBlock - PragueBlock = MainnetConstant.pragueBlock - OsakaBlock = MainnetConstant.osakaBlock - DynamicGasLimitBlock = MainnetConstant.dynamicGasLimitBlock - TIPUpgradeReward = MainnetConstant.tipUpgradeReward - TipUpgradePenalty = MainnetConstant.tipUpgradePenalty - TIPEpochHalving = MainnetConstant.tipEpochHalving - - TRC21IssuerSMC = MainnetConstant.trc21IssuerSMC - XDCXListingSMC = MainnetConstant.xdcxListingSMC - RelayerRegistrationSMC = MainnetConstant.relayerRegistrationSMC - LendingRegistrationSMC = MainnetConstant.lendingRegistrationSMC - ignoreSignerCheckBlockArray = MainnetConstant.ignoreSignerCheckBlockArray denylist = MainnetConstant.denylist ) @@ -192,38 +95,6 @@ func CopyConstants(chainID uint64) { } c.print() - MaxMasternodesV2 = c.maxMasternodesV2 - DenylistHFNumber = c.denylistHFNumber - TIP2019Block = c.tip2019Block - TIPSigning = c.tipSigning - TIPRandomize = c.tipRandomize - TIPNoHalvingMNReward = c.tipNoHalvingMNReward - TIPXDCX = c.tipXDCX - TIPXDCXLending = c.tipXDCXLending - TIPXDCXCancellationFee = c.tipXDCXCancellationFee - TIPTRC21Fee = c.tipTRC21Fee - TIPIncreaseMasternodes = c.tipIncreaseMasternodes - BerlinBlock = c.berlinBlock - LondonBlock = c.londonBlock - MergeBlock = c.mergeBlock - ShanghaiBlock = c.shanghaiBlock - BlockNumberGas50x = c.blockNumberGas50x - TIPXDCXMinerDisable = c.tipXDCXMinerDisable - TIPXDCXReceiverDisable = c.tipXDCXReceiverDisable - Eip1559Block = c.eip1559Block - CancunBlock = c.cancunBlock - PragueBlock = c.pragueBlock - OsakaBlock = c.osakaBlock - DynamicGasLimitBlock = c.dynamicGasLimitBlock - TIPUpgradeReward = c.tipUpgradeReward - TipUpgradePenalty = c.tipUpgradePenalty - TIPEpochHalving = c.tipEpochHalving - - TRC21IssuerSMC = c.trc21IssuerSMC - XDCXListingSMC = c.xdcxListingSMC - RelayerRegistrationSMC = c.relayerRegistrationSMC - LendingRegistrationSMC = c.lendingRegistrationSMC - clear(ignoreSignerCheckBlockArray) maps.Copy(ignoreSignerCheckBlockArray, c.ignoreSignerCheckBlockArray) diff --git a/common/constants.devnet.go b/common/constants.devnet.go index b409d62bf90f..41c1f018d49c 100644 --- a/common/constants.devnet.go +++ b/common/constants.devnet.go @@ -1,45 +1,7 @@ package common -import ( - "math" - "math/big" -) - var DevnetConstant = constant{ - chainID: 5551, - denylistHFNumber: 0, - maxMasternodesV2: 108, - - tip2019Block: big.NewInt(0), - tipSigning: big.NewInt(0), - tipRandomize: big.NewInt(0), - tipNoHalvingMNReward: big.NewInt(0), - tipXDCX: big.NewInt(0), - tipXDCXLending: big.NewInt(0), - tipXDCXCancellationFee: big.NewInt(0), - tipTRC21Fee: big.NewInt(0), - tipIncreaseMasternodes: big.NewInt(0), - berlinBlock: big.NewInt(0), - londonBlock: big.NewInt(0), - mergeBlock: big.NewInt(0), - shanghaiBlock: big.NewInt(0), - blockNumberGas50x: big.NewInt(0), - TIPV2SwitchBlock: big.NewInt(2700), - tipXDCXMinerDisable: big.NewInt(0), - tipXDCXReceiverDisable: big.NewInt(0), - eip1559Block: big.NewInt(250000), - cancunBlock: big.NewInt(250000), - pragueBlock: big.NewInt(5000000), - osakaBlock: big.NewInt(math.MaxInt64), - dynamicGasLimitBlock: big.NewInt(5000000), - tipUpgradeReward: big.NewInt(5000000), - tipUpgradePenalty: big.NewInt(5000000), - tipEpochHalving: big.NewInt(math.MaxInt64), - - trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), - xdcxListingSMC: HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), - relayerRegistrationSMC: HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), - lendingRegistrationSMC: HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + chainID: 5551, ignoreSignerCheckBlockArray: map[uint64]struct{}{ 1032300: {}, diff --git a/common/constants.local.go b/common/constants.local.go index a21b4501e2fd..42f23e4c2a9d 100644 --- a/common/constants.local.go +++ b/common/constants.local.go @@ -1,45 +1,7 @@ package common -import ( - "math" - "math/big" -) - var localConstant = constant{ - chainID: 5151, - maxMasternodesV2: 108, - denylistHFNumber: 0, - - tip2019Block: big.NewInt(0), - tipSigning: big.NewInt(0), - tipRandomize: big.NewInt(0), - tipNoHalvingMNReward: big.NewInt(0), - tipXDCX: big.NewInt(0), - tipXDCXLending: big.NewInt(0), - tipXDCXCancellationFee: big.NewInt(0), - tipTRC21Fee: big.NewInt(0), - tipIncreaseMasternodes: big.NewInt(0), - berlinBlock: big.NewInt(0), - londonBlock: big.NewInt(0), - mergeBlock: big.NewInt(0), - shanghaiBlock: big.NewInt(0), - blockNumberGas50x: big.NewInt(0), - TIPV2SwitchBlock: big.NewInt(0), - tipXDCXMinerDisable: big.NewInt(0), - tipXDCXReceiverDisable: big.NewInt(0), - eip1559Block: big.NewInt(0), - cancunBlock: big.NewInt(0), - pragueBlock: big.NewInt(math.MaxInt64), - osakaBlock: big.NewInt(math.MaxInt64), - dynamicGasLimitBlock: big.NewInt(math.MaxInt64), - tipUpgradeReward: big.NewInt(math.MaxInt64), - tipUpgradePenalty: big.NewInt(math.MaxInt64), - tipEpochHalving: big.NewInt(math.MaxInt64), - - trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), - xdcxListingSMC: HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), - relayerRegistrationSMC: HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), - lendingRegistrationSMC: HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + chainID: 5151, ignoreSignerCheckBlockArray: map[uint64]struct{}{}, diff --git a/common/constants.mainnet.go b/common/constants.mainnet.go index 006b47497ead..0bd66c91139c 100644 --- a/common/constants.mainnet.go +++ b/common/constants.mainnet.go @@ -1,45 +1,7 @@ package common -import ( - "math" - "math/big" -) - var MainnetConstant = constant{ - chainID: 50, - denylistHFNumber: 38383838, - maxMasternodesV2: 108, - - tip2019Block: big.NewInt(1), - tipSigning: big.NewInt(3000000), - tipRandomize: big.NewInt(3464000), - tipNoHalvingMNReward: big.NewInt(38383838), - tipXDCX: big.NewInt(38383838), - tipXDCXLending: big.NewInt(38383838), - tipXDCXCancellationFee: big.NewInt(38383838), - tipTRC21Fee: big.NewInt(38383838), - tipIncreaseMasternodes: big.NewInt(5000000), - berlinBlock: big.NewInt(76321000), // Target 19th June 2024 - londonBlock: big.NewInt(76321000), // Target 19th June 2024 - mergeBlock: big.NewInt(76321000), // Target 19th June 2024 - shanghaiBlock: big.NewInt(76321000), // Target 19th June 2024 - blockNumberGas50x: big.NewInt(80370000), // Target 2nd Oct 2024 - TIPV2SwitchBlock: big.NewInt(80370000), // Target 2nd Oct 2024 - tipXDCXMinerDisable: big.NewInt(80370000), // Target 2nd Oct 2024 - tipXDCXReceiverDisable: big.NewInt(80370900), // Target 2nd Oct 2024, safer to release after disable miner - eip1559Block: big.NewInt(98800200), // Target 28th Jan 2026 - cancunBlock: big.NewInt(98802000), // Target 28th Jan 2026 - pragueBlock: big.NewInt(math.MaxInt64), - osakaBlock: big.NewInt(math.MaxInt64), - dynamicGasLimitBlock: big.NewInt(math.MaxInt64), - tipUpgradeReward: big.NewInt(math.MaxInt64), - tipUpgradePenalty: big.NewInt(math.MaxInt64), - tipEpochHalving: big.NewInt(math.MaxInt64), - - trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), - xdcxListingSMC: HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), - relayerRegistrationSMC: HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), - lendingRegistrationSMC: HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + chainID: 50, ignoreSignerCheckBlockArray: map[uint64]struct{}{ 1032300: {}, diff --git a/common/constants.testnet.go b/common/constants.testnet.go index 541681e4ef73..dbdd2104d799 100644 --- a/common/constants.testnet.go +++ b/common/constants.testnet.go @@ -1,45 +1,7 @@ package common -import ( - "math" - "math/big" -) - var TestnetConstant = constant{ - chainID: 51, - denylistHFNumber: 23779191, - maxMasternodesV2: 15, - - tip2019Block: big.NewInt(1), - tipSigning: big.NewInt(3000000), - tipRandomize: big.NewInt(3464000), - tipNoHalvingMNReward: big.NewInt(23779191), // hardfork no halving masternodes reward - tipXDCX: big.NewInt(23779191), - tipXDCXLending: big.NewInt(23779191), - tipXDCXCancellationFee: big.NewInt(23779191), - tipTRC21Fee: big.NewInt(23779191), - tipIncreaseMasternodes: big.NewInt(5000000), - blockNumberGas50x: big.NewInt(56828700), // Target 13rd Nov 2023 - TIPV2SwitchBlock: big.NewInt(56828700), // Target 13rd Nov 2023 - berlinBlock: big.NewInt(61290000), // Target 31st March 2024 - londonBlock: big.NewInt(61290000), // Target 31st March 2024 - mergeBlock: big.NewInt(61290000), // Target 31st March 2024 - shanghaiBlock: big.NewInt(61290000), // Target 31st March 2024 - tipXDCXMinerDisable: big.NewInt(61290000), // Target 31st March 2024 - tipXDCXReceiverDisable: big.NewInt(66825000), // Target 26 Aug 2024 - eip1559Block: big.NewInt(71550000), // Target 14th Feb 2025 - cancunBlock: big.NewInt(71551800), - pragueBlock: big.NewInt(math.MaxInt64), - osakaBlock: big.NewInt(math.MaxInt64), - dynamicGasLimitBlock: big.NewInt(math.MaxInt64), - tipUpgradeReward: big.NewInt(math.MaxInt64), - tipUpgradePenalty: big.NewInt(math.MaxInt64), - tipEpochHalving: big.NewInt(math.MaxInt64), - - trc21IssuerSMC: HexToAddress("0x0E2C88753131CE01c7551B726b28BFD04e44003F"), - xdcxListingSMC: HexToAddress("0x14B2Bf043b9c31827A472CE4F94294fE9a6277e0"), - relayerRegistrationSMC: HexToAddress("0xA1996F69f47ba14Cb7f661010A7C31974277958c"), - lendingRegistrationSMC: HexToAddress("0x28d7fC2Cf5c18203aaCD7459EFC6Af0643C97bE8"), + chainID: 51, ignoreSignerCheckBlockArray: map[uint64]struct{}{ 1032300: {}, diff --git a/common/gas.go b/common/gas.go index 7f1135ceeaca..8d70fb763a13 100644 --- a/common/gas.go +++ b/common/gas.go @@ -6,32 +6,28 @@ var MinGasPrice50x = big.NewInt(12500000000) var GasPrice50x = big.NewInt(12500000000) var BaseFee = big.NewInt(12500000000) -func GetGasFee(blockNumber, gas uint64) *big.Int { +// GetGasFee returns the effective fee for the given block and gas usage. +func GetGasFee(blockNumber, gas uint64, tipTRC21FeeBlock, gas50xBlock *big.Int) *big.Int { fee := new(big.Int).SetUint64(gas) - - if blockNumber >= BlockNumberGas50x.Uint64() { - fee = fee.Mul(fee, GasPrice50x) - } else if blockNumber > TIPTRC21Fee.Uint64() { - fee = fee.Mul(fee, TRC21GasPrice) - } else { - fee = fee.Mul(fee, TRC21GasPriceBefore) + if gas50xBlock != nil && blockNumber >= gas50xBlock.Uint64() { + return fee.Mul(fee, GasPrice50x) } - - return fee + if tipTRC21FeeBlock != nil && blockNumber > tipTRC21FeeBlock.Uint64() { + return fee.Mul(fee, TRC21GasPrice) + } + return fee.Mul(fee, TRC21GasPriceBefore) } -func GetGasPrice(number *big.Int) *big.Int { - if number == nil || number.Cmp(BlockNumberGas50x) < 0 { - return new(big.Int).Set(TRC21GasPrice) - } else { +func GetGasPrice(number, gas50xBlock *big.Int) *big.Int { + if number != nil && gas50xBlock != nil && number.Cmp(gas50xBlock) >= 0 { return new(big.Int).Set(GasPrice50x) } + return new(big.Int).Set(TRC21GasPrice) } -func GetMinGasPrice(number *big.Int) *big.Int { - if number == nil || number.Cmp(BlockNumberGas50x) < 0 { - return new(big.Int).Set(MinGasPrice) - } else { +func GetMinGasPrice(number, gas50xBlock *big.Int) *big.Int { + if number != nil && gas50xBlock != nil && number.Cmp(gas50xBlock) >= 0 { return new(big.Int).Set(MinGasPrice50x) } + return new(big.Int).Set(MinGasPrice) } diff --git a/common/gas_test.go b/common/gas_test.go new file mode 100644 index 000000000000..b1a1d8cc8db0 --- /dev/null +++ b/common/gas_test.go @@ -0,0 +1,38 @@ +package common + +import ( + "math/big" + "testing" +) + +func TestGetGasFeeUsesGas50xBlock(t *testing.T) { + gas50xBlock := big.NewInt(100) + tipTRC21FeeBlock := big.NewInt(50) + + beforeFork := GetGasFee(99, 2, tipTRC21FeeBlock, gas50xBlock) + if want := new(big.Int).Mul(big.NewInt(2), TRC21GasPrice); beforeFork.Cmp(want) != 0 { + t.Fatalf("unexpected fee before gas50x fork: have %v want %v", beforeFork, want) + } + + afterFork := GetGasFee(100, 2, tipTRC21FeeBlock, gas50xBlock) + if want := new(big.Int).Mul(big.NewInt(2), GasPrice50x); afterFork.Cmp(want) != 0 { + t.Fatalf("unexpected fee after gas50x fork: have %v want %v", afterFork, want) + } +} + +func TestGetGasPriceAndMinGasPriceUseGas50xBlock(t *testing.T) { + gas50xBlock := big.NewInt(100) + + if got := GetGasPrice(big.NewInt(99), gas50xBlock); got.Cmp(TRC21GasPrice) != 0 { + t.Fatalf("unexpected gas price before gas50x fork: have %v want %v", got, TRC21GasPrice) + } + if got := GetGasPrice(big.NewInt(100), gas50xBlock); got.Cmp(GasPrice50x) != 0 { + t.Fatalf("unexpected gas price after gas50x fork: have %v want %v", got, GasPrice50x) + } + if got := GetMinGasPrice(big.NewInt(99), gas50xBlock); got.Cmp(MinGasPrice) != 0 { + t.Fatalf("unexpected min gas price before gas50x fork: have %v want %v", got, MinGasPrice) + } + if got := GetMinGasPrice(big.NewInt(100), gas50xBlock); got.Cmp(MinGasPrice50x) != 0 { + t.Fatalf("unexpected min gas price after gas50x fork: have %v want %v", got, MinGasPrice50x) + } +} diff --git a/consensus/XDPoS/api.go b/consensus/XDPoS/api.go index 3bace2c902b6..abdfd9366423 100644 --- a/consensus/XDPoS/api.go +++ b/consensus/XDPoS/api.go @@ -371,12 +371,13 @@ func (api *API) GetV2BlockByHash(blockHash common.Hash) *V2BlockInfo { func (api *API) NetworkInformation() NetworkInformation { info := NetworkInformation{} - info.NetworkId = api.chain.Config().ChainID + config := api.chain.Config() + info.NetworkId = config.ChainID info.XDCValidatorAddress = common.MasternodeVotingSMCBinary - info.LendingAddress = common.LendingRegistrationSMC - info.RelayerRegistrationAddress = common.RelayerRegistrationSMC - info.XDCXListingAddress = common.XDCXListingSMC - info.XDCZAddress = common.TRC21IssuerSMC + info.LendingAddress = config.LendingRegistrationSMC + info.RelayerRegistrationAddress = config.RelayerRegistrationSMC + info.XDCXListingAddress = config.XDCXListingSMC + info.XDCZAddress = config.TRC21IssuerSMC info.ConsensusConfigs = *api.XDPoS.config return info diff --git a/consensus/XDPoS/engines/engine_v1/engine.go b/consensus/XDPoS/engines/engine_v1/engine.go index cfa11cdf4d54..da916c7b88f4 100644 --- a/consensus/XDPoS/engines/engine_v1/engine.go +++ b/consensus/XDPoS/engines/engine_v1/engine.go @@ -792,7 +792,7 @@ func (x *XDPoS_v1) UpdateMasternodes(chain consensus.ChainReader, header *types. // check if block number is increase ms checkpoint if x.chainConfig.IsTIPIncreaseMasternodes(header.Number) || (x.config.V2.SwitchBlock != nil && header.Number.Cmp(x.config.V2.SwitchBlock) == 1) { // using new masterndoes - maxMasternodes = common.MaxMasternodesV2 + maxMasternodes = x.chainConfig.XDPoS.MaxMasternodesV2 } else { // using old masterndoes maxMasternodes = common.MaxMasternodes diff --git a/consensus/XDPoS/engines/engine_v1/utils_test.go b/consensus/XDPoS/engines/engine_v1/utils_test.go index 568bbd92099f..f9fb9b5d71cb 100644 --- a/consensus/XDPoS/engines/engine_v1/utils_test.go +++ b/consensus/XDPoS/engines/engine_v1/utils_test.go @@ -23,6 +23,7 @@ func TestGetM1M2FromCheckpointHeader(t *testing.T) { } epoch := uint64(900) config := ¶ms.ChainConfig{ + TIPRandomizeBlock: big.NewInt(3464000), XDPoS: ¶ms.XDPoSConfig{ Epoch: epoch, }, diff --git a/consensus/tests/engine_v1_tests/helper.go b/consensus/tests/engine_v1_tests/helper.go index 1f887437bd30..3d825431aa82 100644 --- a/consensus/tests/engine_v1_tests/helper.go +++ b/consensus/tests/engine_v1_tests/helper.go @@ -74,10 +74,13 @@ func RandStringBytes(n int) string { func getCommonBackend(t *testing.T, chainConfig *params.ChainConfig) *backends.SimulatedBackend { // initial helper backend contractBackendForSC := backends.NewXDCSimulatedBackend(types.GenesisAlloc{ - voterAddr: {Balance: new(big.Int).SetUint64(10000000000)}, + voterAddr: {Balance: new(big.Int).SetUint64(1000000000000000000)}, }, 10000000, chainConfig) - transactOpts := bind.NewKeyedTransactor(voterKey) + transactOpts, err := bind.NewKeyedTransactorWithChainID(voterKey, chainConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } var candidates []common.Address var caps []*big.Int @@ -225,8 +228,40 @@ func GetCandidateFromCurrentSmartContract(backend bind.ContractBackend, t *testi return ms } +func legacyV1TestChainConfig(chainConfig *params.ChainConfig) *params.ChainConfig { + if chainConfig == nil { + return nil + } + legacy := *chainConfig + futureForkBlock := big.NewInt(1_000_000_000) + legacy.TIP2019Block = new(big.Int).Set(futureForkBlock) + legacy.PetersburgBlock = new(big.Int).Set(futureForkBlock) + legacy.IstanbulBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPSigningBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPRandomizeBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPIncreaseMasternodesBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPNoHalvingMNRewardBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPXDCXBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPXDCXLendingBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPXDCXCancellationFeeBlock = new(big.Int).Set(futureForkBlock) + legacy.BerlinBlock = new(big.Int).Set(futureForkBlock) + legacy.LondonBlock = new(big.Int).Set(futureForkBlock) + legacy.MergeBlock = new(big.Int).Set(futureForkBlock) + legacy.ShanghaiBlock = new(big.Int).Set(futureForkBlock) + legacy.Eip1559Block = new(big.Int).Set(futureForkBlock) + legacy.CancunBlock = new(big.Int).Set(futureForkBlock) + legacy.PragueBlock = new(big.Int).Set(futureForkBlock) + legacy.OsakaBlock = new(big.Int).Set(futureForkBlock) + legacy.DynamicGasLimitBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPUpgradeRewardBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPUpgradePenaltyBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPEpochHalvingBlock = new(big.Int).Set(futureForkBlock) + return &legacy +} + // V1 consensus engine func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error)) { + chainConfig = legacyV1TestChainConfig(chainConfig) // Preparation var err error // Authorise @@ -356,6 +391,9 @@ func createBlockFromHeader(bc *core.BlockChain, customHeader *types.Header, txs Validators: customHeader.Validators, Penalties: customHeader.Penalties, } + if config != nil && config.IsEIP1559(header.Number) { + header.BaseFee = new(big.Int).Set(common.BaseFee) + } var block *types.Block if len(txs) == 0 { block = types.NewBlockWithHeader(&header) diff --git a/consensus/tests/engine_v2_tests/authorised_masternode_test.go b/consensus/tests/engine_v2_tests/authorised_masternode_test.go index 9ea21232ec4c..5225ac2e23a6 100644 --- a/consensus/tests/engine_v2_tests/authorised_masternode_test.go +++ b/consensus/tests/engine_v2_tests/authorised_masternode_test.go @@ -109,7 +109,8 @@ func TestIsYourTurnConsensusV2CrossConfig(t *testing.T) { // after new mine period secondMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod - time.Sleep(time.Duration(secondMinePeriod-firstMinePeriod) * time.Second) + // YourTurn uses Unix-second granularity; add a small buffer to avoid edge-time flakiness. + time.Sleep(time.Duration(secondMinePeriod-firstMinePeriod+1) * time.Second) isYourTurn, err = adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc703c4b2bD70c169f5717101CaeE543299Fc946C7")) assert.Nil(t, err) assert.True(t, isYourTurn) diff --git a/consensus/tests/engine_v2_tests/helper.go b/consensus/tests/engine_v2_tests/helper.go index 284b3f39dba1..9d6e4501bbb1 100644 --- a/consensus/tests/engine_v2_tests/helper.go +++ b/consensus/tests/engine_v2_tests/helper.go @@ -133,10 +133,13 @@ func voteTX(gasLimit uint64, nonce uint64, addr string) (*types.Transaction, err func getCommonBackend(t *testing.T, chainConfig *params.ChainConfig) *backends.SimulatedBackend { // initial helper backend contractBackendForSC := backends.NewXDCSimulatedBackend(types.GenesisAlloc{ - voterAddr: {Balance: new(big.Int).SetUint64(10000000000)}, + voterAddr: {Balance: new(big.Int).SetUint64(1000000000000000000)}, }, 10000000, chainConfig) - transactOpts := bind.NewKeyedTransactor(voterKey) + transactOpts, err := bind.NewKeyedTransactorWithChainID(voterKey, chainConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } var candidates []common.Address var caps []*big.Int @@ -209,10 +212,13 @@ func getMultiCandidatesBackend(t *testing.T, chainConfig *params.ChainConfig, n assert.GreaterOrEqual(t, n, 4) // initial helper backend, give a very large gas limit contractBackendForSC := backends.NewXDCSimulatedBackend(types.GenesisAlloc{ - voterAddr: {Balance: new(big.Int).SetUint64(10000000000)}, + voterAddr: {Balance: new(big.Int).SetUint64(1000000000000000000)}, }, 1000000000, chainConfig) - transactOpts := bind.NewKeyedTransactor(voterKey) + transactOpts, err := bind.NewKeyedTransactorWithChainID(voterKey, chainConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } var candidates []common.Address var caps []*big.Int @@ -285,10 +291,13 @@ func getMultiCandidatesBackend(t *testing.T, chainConfig *params.ChainConfig, n func getProtectorObserverBackend(t *testing.T, chainConfig *params.ChainConfig) *backends.SimulatedBackend { // initial helper backend contractBackendForSC := backends.NewXDCSimulatedBackend(types.GenesisAlloc{ - voterAddr: {Balance: new(big.Int).SetUint64(10000000000)}, + voterAddr: {Balance: new(big.Int).SetUint64(1000000000000000000)}, }, 10000000, chainConfig) - transactOpts := bind.NewKeyedTransactor(voterKey) + transactOpts, err := bind.NewKeyedTransactorWithChainID(voterKey, chainConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } var candidates []common.Address var caps []*big.Int @@ -427,6 +436,30 @@ func GetCandidateFromCurrentSmartContract(backend bind.ContractBackend, t *testi return ms } +func legacyExecutionConfigForV2Tests(chainConfig *params.ChainConfig) *params.ChainConfig { + if chainConfig == nil { + return nil + } + legacy := *chainConfig + futureForkBlock := big.NewInt(1_000_000_000) + legacy.PetersburgBlock = new(big.Int).Set(futureForkBlock) + legacy.IstanbulBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPIncreaseMasternodesBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPXDCXBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPXDCXLendingBlock = new(big.Int).Set(futureForkBlock) + legacy.TIPXDCXCancellationFeeBlock = new(big.Int).Set(futureForkBlock) + legacy.BerlinBlock = new(big.Int).Set(futureForkBlock) + legacy.LondonBlock = new(big.Int).Set(futureForkBlock) + legacy.MergeBlock = new(big.Int).Set(futureForkBlock) + legacy.ShanghaiBlock = new(big.Int).Set(futureForkBlock) + legacy.Eip1559Block = new(big.Int).Set(futureForkBlock) + legacy.CancunBlock = new(big.Int).Set(futureForkBlock) + legacy.PragueBlock = new(big.Int).Set(futureForkBlock) + legacy.OsakaBlock = new(big.Int).Set(futureForkBlock) + legacy.DynamicGasLimitBlock = new(big.Int).Set(futureForkBlock) + return &legacy +} + type ForkedBlockOptions struct { numOfForkedBlocks *int forkedRoundDifference *int // Minimum is 1 @@ -435,6 +468,7 @@ type ForkedBlockOptions struct { // V2 consensus engine func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig, forkedBlockOptions *ForkedBlockOptions) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error), *types.Block) { + chainConfig = legacyExecutionConfigForV2Tests(chainConfig) // Preparation var err error signer, signFn, err := backends.SimulateWalletAddressAndSignFn() @@ -526,6 +560,7 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon // V2 consensus engine, compared to PrepareXDCTestBlockChainForV2Engine: (1) no forking (2) add penalty func PrepareXDCTestBlockChainWithPenaltyForV2Engine(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error)) { + chainConfig = legacyExecutionConfigForV2Tests(chainConfig) // Preparation var err error signer, signFn, err := backends.SimulateWalletAddressAndSignFn() @@ -582,6 +617,7 @@ func PrepareXDCTestBlockChainWithPenaltyForV2Engine(t *testing.T, numOfBlocks in // V2 consensus engine, compared to PrepareXDCTestBlockChainForV2Engine: (1) no forking (2) add penalty func PrepareXDCTestBlockChainWithPenaltyCustomized(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig, penaltyOrNot []bool) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error)) { + chainConfig = legacyExecutionConfigForV2Tests(chainConfig) // Preparation var err error signer, signFn, err := backends.SimulateWalletAddressAndSignFn() @@ -645,6 +681,7 @@ func PrepareXDCTestBlockChainWithPenaltyCustomized(t *testing.T, numOfBlocks int // V2 consensus engine, compared to PrepareXDCTestBlockChainForV2Engine: (1) no forking (2) 128 masternode candidates func PrepareXDCTestBlockChainWith128Candidates(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error)) { + chainConfig = legacyExecutionConfigForV2Tests(chainConfig) // Preparation var err error signer, signFn, err := backends.SimulateWalletAddressAndSignFn() @@ -709,6 +746,7 @@ func PrepareXDCTestBlockChainWith128Candidates(t *testing.T, numOfBlocks int, ch // V2 consensus engine func PrepareXDCTestBlockChainWithProtectorObserver(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error)) { + chainConfig = legacyExecutionConfigForV2Tests(chainConfig) // Preparation var err error signer, signFn, err := backends.SimulateWalletAddressAndSignFn() @@ -888,6 +926,9 @@ func createBlockFromHeader(bc *core.BlockChain, customHeader *types.Header, txs Validators: customHeader.Validators, Penalties: customHeader.Penalties, } + if config != nil && config.IsEIP1559(header.Number) { + header.BaseFee = new(big.Int).Set(common.BaseFee) + } var block *types.Block if len(txs) == 0 { // Sign all the things and seal it diff --git a/consensus/tests/engine_v2_tests/penalty_test.go b/consensus/tests/engine_v2_tests/penalty_test.go index 7658d57d4c7d..2eb20423f500 100644 --- a/consensus/tests/engine_v2_tests/penalty_test.go +++ b/consensus/tests/engine_v2_tests/penalty_test.go @@ -162,19 +162,26 @@ func TestGetPenalties(t *testing.T) { // but if it does not stays enough, it will still be penalty. func TestHookPenaltyParolee(t *testing.T) { skipLongInShortMode(t) - // set upgrade number to 0 - backup := common.TipUpgradePenalty - common.TipUpgradePenalty = big.NewInt(0) + b, err := json.Marshal(params.TestXDPoSMockChainConfig) + assert.Nil(t, err) - config := params.TestXDPoSMockChainConfig - blockchain, _, _, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, int(config.XDPoS.Epoch)*4, config) + var config params.ChainConfig + err = json.Unmarshal(b, &config) + assert.Nil(t, err) + config.TIPUpgradePenaltyBlock = big.NewInt(0) + b, err = json.Marshal(config) + assert.Nil(t, err) + err = json.Unmarshal(b, &config) + assert.Nil(t, err) + + blockchain, _, _, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, int(config.XDPoS.Epoch)*4, &config) adaptor := blockchain.Engine().(*XDPoS.XDPoS) - hooks.AttachConsensusV2Hooks(adaptor, blockchain, config) + hooks.AttachConsensusV2Hooks(adaptor, blockchain, &config) assert.NotNil(t, adaptor.EngineV2.HookPenalty) var extraField types.ExtraFields_v2 // 901 is the first v2 block header901 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch + 1) - err := utils.DecodeBytesExtraFields(header901.Extra, &extraField) + err = utils.DecodeBytesExtraFields(header901.Extra, &extraField) assert.Nil(t, err) masternodes := adaptor.GetMasternodesFromCheckpointHeader(header901) assert.Equal(t, 5, len(masternodes)) @@ -211,7 +218,6 @@ func TestHookPenaltyParolee(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 1, len(penalty)) - common.TipUpgradePenalty = backup } // TestHookPenaltyParoleePerformance tests penalty hook performance @@ -225,10 +231,11 @@ func TestHookPenaltyParoleePerformance(t *testing.T) { err = json.Unmarshal([]byte(configString), &config) assert.Nil(t, err) config.XDPoS.V2.AllConfigs[900].LimitPenaltyEpoch = 4 - - // set upgrade number to 0 - backup := common.TipUpgradePenalty - common.TipUpgradePenalty = big.NewInt(0) + config.TIPUpgradePenaltyBlock = big.NewInt(0) + b, err = json.Marshal(config) + assert.Nil(t, err) + err = json.Unmarshal(b, &config) + assert.Nil(t, err) // 900 1800 2700 3600(not) 4500 5400 has penalty except 3600 penaltyOrNot := []bool{true, true, true, false, true, true} @@ -261,5 +268,4 @@ func TestHookPenaltyParoleePerformance(t *testing.T) { // miner (coinbase) is not parolee since one epoch it is not penalty. so it is in penalty. plus another one, total 2. assert.Equal(t, 2, len(penalty)) - common.TipUpgradePenalty = backup } diff --git a/consensus/tests/engine_v2_tests/reward_test.go b/consensus/tests/engine_v2_tests/reward_test.go index 51eb0f3aa8de..6b905f6a8819 100644 --- a/consensus/tests/engine_v2_tests/reward_test.go +++ b/consensus/tests/engine_v2_tests/reward_test.go @@ -179,9 +179,11 @@ func TestHookRewardAfterUpgrade(t *testing.T) { // set switch to 1800, so that it covers 901-1799, 1800-2700 two epochs config.XDPoS.V2.SwitchBlock.SetUint64(1800) config.XDPoS.V2.SwitchEpoch = 2 - // set upgrade number to 0 - backup := common.TIPUpgradeReward - common.TIPUpgradeReward = big.NewInt(0) + config.TIPUpgradeRewardBlock = big.NewInt(0) + b, err = json.Marshal(config) + assert.Nil(t, err) + err = json.Unmarshal(b, &config) + assert.Nil(t, err) blockchain, _, _, signer, signFn := PrepareXDCTestBlockChainWithProtectorObserver(t, int(config.XDPoS.Epoch)*3+10, &config) @@ -312,7 +314,6 @@ func TestHookRewardAfterUpgrade(t *testing.T) { totalBurned := statedb.GetPostBurned(epochNum).Big().Int64() // since no EIP 1559, so no burned assert.Zero(t, totalBurned, "statedb records wrong total burned") - common.TIPUpgradeReward = backup } func TestFinalizeAfterUpgrade(t *testing.T) { @@ -327,9 +328,11 @@ func TestFinalizeAfterUpgrade(t *testing.T) { // set switch to 1800, so that it covers 901-1799, 1800-2700 two epochs config.XDPoS.V2.SwitchBlock.SetUint64(1800) config.XDPoS.V2.SwitchEpoch = 2 - // set upgrade number to 0 - backup := common.TIPUpgradeReward - common.TIPUpgradeReward = big.NewInt(0) + config.TIPUpgradeRewardBlock = big.NewInt(0) + b, err = json.Marshal(config) + assert.Nil(t, err) + err = json.Unmarshal(b, &config) + assert.Nil(t, err) blockchain, _, _, signer, signFn := PrepareXDCTestBlockChainWithProtectorObserver(t, int(config.XDPoS.Epoch)*3+10, &config) @@ -381,7 +384,6 @@ func TestFinalizeAfterUpgrade(t *testing.T) { minted := statedbAfterFinalize.GetPostMinted(epochNum) assert.False(t, minted.IsZero()) - common.TIPUpgradeReward = backup } func TestRewardHalvingVanishing(t *testing.T) { diff --git a/consensus/tests/engine_v2_tests/verify_header_test.go b/consensus/tests/engine_v2_tests/verify_header_test.go index 0ae2066eda39..4f444b523d1a 100644 --- a/consensus/tests/engine_v2_tests/verify_header_test.go +++ b/consensus/tests/engine_v2_tests/verify_header_test.go @@ -469,12 +469,12 @@ func TestShouldVerifyHeadersEvenIfParentsNotYetWrittenIntoDB(t *testing.T) { // Create block 911 but don't write into DB blockNumber := 911 roundNumber := int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64() - block911 := CreateBlock(blockchain, &config, block910, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil, "") + block911 := CreateBlock(blockchain, blockchain.Config(), block910, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil, "") // Create block 912 and not write into DB as well blockNumber = 912 roundNumber = int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64() - block912 := CreateBlock(blockchain, &config, block911, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil, "") + block912 := CreateBlock(blockchain, blockchain.Config(), block911, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil, "") headersTobeVerified = append(headersTobeVerified, block910.Header(), block911.Header(), block912.Header()) // Randomly set full verify @@ -561,7 +561,7 @@ func TestShouldVerifyPureV2EpochSwitchHeadersEvenIfParentNotYetWrittenIntoDB(t * block1799 := CreateBlock( blockchain, - &config, + blockchain.Config(), block1798, 1799, int64(1799)-config.XDPoS.V2.SwitchBlock.Int64(), @@ -574,7 +574,7 @@ func TestShouldVerifyPureV2EpochSwitchHeadersEvenIfParentNotYetWrittenIntoDB(t * ) block1800 := CreateBlock( blockchain, - &config, + blockchain.Config(), block1799, 1800, int64(1800)-config.XDPoS.V2.SwitchBlock.Int64(), @@ -636,7 +636,7 @@ func TestVerifyHeadersDoesNotFabricateBatchBlocksForHookPenalty(t *testing.T) { block1799 := CreateBlock( blockchain, - &config, + blockchain.Config(), block1798, 1799, int64(1799)-config.XDPoS.V2.SwitchBlock.Int64(), @@ -649,7 +649,7 @@ func TestVerifyHeadersDoesNotFabricateBatchBlocksForHookPenalty(t *testing.T) { ) block1800 := CreateBlock( blockchain, - &config, + blockchain.Config(), block1799, 1800, int64(1800)-config.XDPoS.V2.SwitchBlock.Int64(), diff --git a/contracts/blocksigner/blocksigner_test.go b/contracts/blocksigner/blocksigner_test.go index a9ed2ef26b4b..17a2006d0be7 100644 --- a/contracts/blocksigner/blocksigner_test.go +++ b/contracts/blocksigner/blocksigner_test.go @@ -37,8 +37,11 @@ var ( ) func TestBlockSigner(t *testing.T) { - contractBackend := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000, params.TestXDPoSMockChainConfig) - transactOpts := bind.NewKeyedTransactor(key) + contractBackend := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1000))}}, 10000000, params.TestXDPoSMockChainConfig) + transactOpts, err := bind.NewKeyedTransactorWithChainID(key, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } blockSignerAddress, blockSigner, err := DeployBlockSigner(transactOpts, contractBackend, big.NewInt(99)) if err != nil { diff --git a/contracts/randomize/randomize_test.go b/contracts/randomize/randomize_test.go index 8588bd8fe310..326a3b1eaf62 100644 --- a/contracts/randomize/randomize_test.go +++ b/contracts/randomize/randomize_test.go @@ -41,8 +41,11 @@ var ( ) func TestRandomize(t *testing.T) { - contractBackend := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(100000000000000)}}, 10000000, params.TestXDPoSMockChainConfig) - transactOpts := bind.NewKeyedTransactor(key) + contractBackend := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1000))}}, 10000000, params.TestXDPoSMockChainConfig) + transactOpts, err := bind.NewKeyedTransactorWithChainID(key, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } transactOpts.GasLimit = 1000000 randomizeAddress, randomize, err := DeployRandomize(transactOpts, contractBackend) @@ -72,13 +75,24 @@ func TestRandomize(t *testing.T) { func TestSendTxRandomizeSecretAndOpening(t *testing.T) { genesis := types.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000000)}} - // TODO(daniel): replace NewSimulatedBackend with NewXDCSimulatedBackend - backend := backends.NewSimulatedBackend(genesis, 42000000) + // Keep this test on a legacy tx path. NewSimulatedBackend now uses + // AllEthashProtocolChanges with post-London forks enabled, which switches + // contract deployment to dynamic-fee txs and breaks this legacy-signer flow. + legacyConfig := *params.AllEthashProtocolChanges + futureForkBlock := big.NewInt(1_000_000_000) + legacyConfig.Eip1559Block = new(big.Int).Set(futureForkBlock) + legacyConfig.CancunBlock = new(big.Int).Set(futureForkBlock) + legacyConfig.PragueBlock = new(big.Int).Set(futureForkBlock) + legacyConfig.OsakaBlock = new(big.Int).Set(futureForkBlock) + backend := backends.NewXDCSimulatedBackend(genesis, 42000000, &legacyConfig) backend.Commit() signer := types.HomesteadSigner{} ctx := context.Background() - transactOpts := bind.NewKeyedTransactor(acc1Key) + transactOpts, err := bind.NewKeyedTransactorWithChainID(acc1Key, legacyConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } transactOpts.GasLimit = 4200000 epocNumber := uint64(900) randomizeAddr, randomizeContract, err := DeployRandomize(transactOpts, backend) diff --git a/contracts/tests/Inherited_test.go b/contracts/tests/Inherited_test.go index 45c472207be1..27af9a4a6462 100644 --- a/contracts/tests/Inherited_test.go +++ b/contracts/tests/Inherited_test.go @@ -8,7 +8,6 @@ import ( "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends" - "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/log" @@ -25,11 +24,8 @@ func TestPriceFeed(t *testing.T) { glogger.Verbosity(log.LevelTrace) log.SetDefault(log.NewLogger(glogger)) - oldTIPXDCXCancellationFee := new(big.Int).Set(common.TIPXDCXCancellationFee) - defer func() { - common.TIPXDCXCancellationFee = oldTIPXDCXCancellationFee - }() - common.TIPXDCXCancellationFee = big.NewInt(0) + testChainConfig := *params.TestXDPoSMockChainConfig + testChainConfig.TIPXDCXCancellationFeeBlock = big.NewInt(0) // init genesis contractBackend := backends.NewXDCSimulatedBackend( @@ -37,9 +33,12 @@ func TestPriceFeed(t *testing.T) { mainAddr: {Balance: big.NewInt(0).Mul(big.NewInt(10000000000000), big.NewInt(10000000000000))}, }, 42000000, - params.TestXDPoSMockChainConfig, + &testChainConfig, ) - transactOpts := bind.NewKeyedTransactor(mainKey) + transactOpts, err := bind.NewKeyedTransactorWithChainID(mainKey, testChainConfig.ChainID) + if err != nil { + t.Fatal("can't create transactor: ", err) + } // deploy payer swap SMC addr, contract, err := DeployMyInherited(transactOpts, contractBackend) if err != nil { diff --git a/contracts/trc21issuer/simulation/test/main.go b/contracts/trc21issuer/simulation/test/main.go index 2c83fd9c6052..856da3fa78ec 100644 --- a/contracts/trc21issuer/simulation/test/main.go +++ b/contracts/trc21issuer/simulation/test/main.go @@ -14,10 +14,12 @@ import ( "github.com/XinFinOrg/XDPoSChain/contracts/trc21issuer" "github.com/XinFinOrg/XDPoSChain/contracts/trc21issuer/simulation" "github.com/XinFinOrg/XDPoSChain/ethclient" + "github.com/XinFinOrg/XDPoSChain/params" ) var ( trc21TokenAddr = common.HexToAddress("0x80430A33EaB86890a346bCf64F86CFeAC73287f3") + chainConfig = params.XDCMainnetChainConfig ) func airDropTokenToAccountNoXDC() { @@ -32,7 +34,7 @@ func airDropTokenToAccountNoXDC() { mainAccount.GasLimit = uint64(4000000) // in units mainAccount.GasPrice = big.NewInt(0).Lsh(common.TRC21GasPrice, 1) trc21Instance, _ := trc21issuer.NewTRC21(mainAccount, trc21TokenAddr, client) - trc21IssuerInstance, _ := trc21issuer.NewTRC21Issuer(mainAccount, common.TRC21IssuerSMC, client) + trc21IssuerInstance, _ := trc21issuer.NewTRC21Issuer(mainAccount, chainConfig.TRC21IssuerSMC, client) // air drop token remainFee, _ := trc21IssuerInstance.GetTokenCapacity(trc21TokenAddr) tx, err := trc21Instance.Transfer(simulation.AirdropAddr, simulation.AirDropAmount) @@ -51,7 +53,7 @@ func airDropTokenToAccountNoXDC() { } gasUsed := hexutil.MustDecodeUint64(receipt["gasUsed"].(string)) blockNumber := hexutil.MustDecodeUint64(receipt["blockNumber"].(string)) - fee := common.GetGasFee(blockNumber, gasUsed) + fee := common.GetGasFee(blockNumber, gasUsed, chainConfig.TIPTRC21FeeBlock, chainConfig.Gas50xBlock) fmt.Println("fee", fee.Uint64(), "number", blockNumber) remainFee = big.NewInt(0).Sub(remainFee, fee) //check balance fee @@ -78,7 +80,7 @@ func testTransferTRC21TokenWithAccountNoXDC() { airDropAccount.GasLimit = uint64(4000000) // in units airDropAccount.GasPrice = big.NewInt(0).Lsh(common.TRC21GasPrice, 1) trc21Instance, _ := trc21issuer.NewTRC21(airDropAccount, trc21TokenAddr, client) - trc21IssuerInstance, _ := trc21issuer.NewTRC21Issuer(airDropAccount, common.TRC21IssuerSMC, client) + trc21IssuerInstance, _ := trc21issuer.NewTRC21Issuer(airDropAccount, chainConfig.TRC21IssuerSMC, client) remainFee, _ := trc21IssuerInstance.GetTokenCapacity(trc21TokenAddr) airDropBalanceBefore, _ := trc21Instance.BalanceOf(simulation.AirdropAddr) @@ -114,7 +116,7 @@ func testTransferTRC21TokenWithAccountNoXDC() { } gasUsed := hexutil.MustDecodeUint64(receipt["gasUsed"].(string)) blockNumber := hexutil.MustDecodeUint64(receipt["blockNumber"].(string)) - fee := common.GetGasFee(blockNumber, gasUsed) + fee := common.GetGasFee(blockNumber, gasUsed, chainConfig.TIPTRC21FeeBlock, chainConfig.Gas50xBlock) fmt.Println("fee", fee.Uint64(), "number", blockNumber) remainFee = big.NewInt(0).Sub(remainFee, fee) //check balance fee @@ -123,7 +125,7 @@ func testTransferTRC21TokenWithAccountNoXDC() { log.Fatal("can't get balance token fee in smart contract: ", err, "got", balanceIssuerFee, "wanted", remainFee) } //check trc21 SMC balance - balance, err = client.BalanceAt(context.Background(), common.TRC21IssuerSMC, nil) + balance, err = client.BalanceAt(context.Background(), chainConfig.TRC21IssuerSMC, nil) if err != nil || balance.Cmp(remainFee) != 0 { log.Fatal("can't get balance token fee in smart contract: ", err, "got", balanceIssuerFee, "wanted", remainFee) } @@ -141,7 +143,7 @@ func testTransferTrc21Fail() { airDropAccount.GasLimit = uint64(4000000) // in units airDropAccount.GasPrice = big.NewInt(0).Lsh(common.TRC21GasPrice, 1) trc21Instance, _ := trc21issuer.NewTRC21(airDropAccount, trc21TokenAddr, client) - trc21IssuerInstance, _ := trc21issuer.NewTRC21Issuer(airDropAccount, common.TRC21IssuerSMC, client) + trc21IssuerInstance, _ := trc21issuer.NewTRC21Issuer(airDropAccount, chainConfig.TRC21IssuerSMC, client) balanceIssuerFee, _ := trc21IssuerInstance.GetTokenCapacity(trc21TokenAddr) minFee, err := trc21Instance.MinFee() @@ -181,7 +183,7 @@ func testTransferTrc21Fail() { } gasUsed := hexutil.MustDecodeUint64(receipt["gasUsed"].(string)) blockNumber := hexutil.MustDecodeUint64(receipt["blockNumber"].(string)) - fee := common.GetGasFee(blockNumber, gasUsed) + fee := common.GetGasFee(blockNumber, gasUsed, chainConfig.TIPTRC21FeeBlock, chainConfig.Gas50xBlock) fmt.Println("fee", fee.Uint64(), "number", blockNumber) remainFee = big.NewInt(0).Sub(remainFee, fee) //check balance fee @@ -190,7 +192,7 @@ func testTransferTrc21Fail() { log.Fatal("can't get balance token fee in smart contract: ", err, "got", balanceIssuerFee, "wanted", remainFee) } //check trc21 SMC balance - balance, err = client.BalanceAt(context.Background(), common.TRC21IssuerSMC, nil) + balance, err = client.BalanceAt(context.Background(), chainConfig.TRC21IssuerSMC, nil) if err != nil || balance.Cmp(remainFee) != 0 { log.Fatal("can't get balance token fee in smart contract: ", err, "got", balanceIssuerFee, "wanted", remainFee) } diff --git a/contracts/trc21issuer/trc21issuer_test.go b/contracts/trc21issuer/trc21issuer_test.go index 6163582d969e..d4573748d92f 100644 --- a/contracts/trc21issuer/trc21issuer_test.go +++ b/contracts/trc21issuer/trc21issuer_test.go @@ -32,6 +32,8 @@ func TestFeeTxWithTRC21Token(t *testing.T) { common.TRC21GasPriceBefore = oldTRC21GasPriceBefore }() common.TRC21GasPriceBefore = big.NewInt(1) + chainConfig := params.TestXDPoSMockChainConfig.Clone() + chainConfig.TRC21IssuerSMC = crypto.CreateAddress(mainAddr, 0) // init genesis contractBackend := backends.NewXDCSimulatedBackend( @@ -39,9 +41,12 @@ func TestFeeTxWithTRC21Token(t *testing.T) { mainAddr: {Balance: big.NewInt(0).Mul(big.NewInt(10000000000000), big.NewInt(10000000000000))}, }, 42000000, - params.TestXDPoSMockChainConfig, + chainConfig, ) - transactOpts := bind.NewKeyedTransactor(mainKey) + transactOpts, err := bind.NewKeyedTransactorWithChainID(mainKey, chainConfig.ChainID) + if err != nil { + t.Fatal("can't create transactor: ", err) + } // deploy payer swap SMC trc21IssuerAddr, trc21Issuer, err := DeployTRC21Issuer(transactOpts, contractBackend, minApply) @@ -50,13 +55,6 @@ func TestFeeTxWithTRC21Token(t *testing.T) { } contractBackend.Commit() - // set contract address to config - oldTRC21IssuerSMC := common.TRC21IssuerSMC - defer func() { - common.TRC21IssuerSMC = oldTRC21IssuerSMC - }() - common.TRC21IssuerSMC = trc21IssuerAddr - cap := big.NewInt(0).Mul(big.NewInt(10000000), big.NewInt(10000000000000)) TRC21fee := big.NewInt(100) @@ -99,7 +97,7 @@ func TestFeeTxWithTRC21Token(t *testing.T) { if err != nil { t.Fatal("can't transaction's receipt ", err, "hash", tx.Hash()) } - fee := common.GetGasFee(receipt.Logs[0].BlockNumber, receipt.GasUsed) + fee := common.GetGasFee(receipt.Logs[0].BlockNumber, receipt.GasUsed, params.TestXDPoSMockChainConfig.TIPTRC21FeeBlock, params.TestXDPoSMockChainConfig.Gas50xBlock) remainFee := big.NewInt(0).Sub(minApply, fee) // check balance trc21 again @@ -123,7 +121,10 @@ func TestFeeTxWithTRC21Token(t *testing.T) { } // access to address which received token trc21 but dont have XDC - key1TransactOpts := bind.NewKeyedTransactor(airdropKey) + key1TransactOpts, err := bind.NewKeyedTransactorWithChainID(airdropKey, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatal("can't create airdrop transactor: ", err) + } key1Trc20, _ := NewTRC21(key1TransactOpts, trc21TokenAddr, contractBackend) transferAmount := big.NewInt(100000) @@ -151,7 +152,7 @@ func TestFeeTxWithTRC21Token(t *testing.T) { if err != nil { t.Fatal("can't transaction's receipt ", err, "hash", tx.Hash()) } - fee = common.GetGasFee(receipt.Logs[0].BlockNumber, receipt.GasUsed) + fee = common.GetGasFee(receipt.Logs[0].BlockNumber, receipt.GasUsed, params.TestXDPoSMockChainConfig.TIPTRC21FeeBlock, params.TestXDPoSMockChainConfig.Gas50xBlock) remainFee = big.NewInt(0).Sub(remainFee, fee) // check balance fee balanceIssuerFee, err = trc21Issuer.GetTokenCapacity(trc21TokenAddr) diff --git a/contracts/utils.go b/contracts/utils.go index c0e336df475c..9e5e77f8dc21 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -421,15 +421,15 @@ func GetCandidatesOwnerBySigner(statedb *state.StateDB, signerAddr common.Addres return statedb.GetCandidateOwner(signerAddr) } -func CalculateRewardForHolders(foundationWalletAddr common.Address, state *state.StateDB, signer common.Address, calcReward *big.Int, blockNumber uint64) (map[common.Address]*big.Int, error) { - rewards, err := GetRewardBalancesRate(foundationWalletAddr, state, signer, calcReward, blockNumber) +func CalculateRewardForHolders(chainConfig *params.ChainConfig, foundationWalletAddr common.Address, state *state.StateDB, signer common.Address, calcReward *big.Int, blockNumber *big.Int) (map[common.Address]*big.Int, error) { + rewards, err := GetRewardBalancesRate(chainConfig, foundationWalletAddr, state, signer, calcReward, blockNumber) if err != nil { return nil, err } return rewards, nil } -func GetRewardBalancesRate(foundationWalletAddr common.Address, statedb *state.StateDB, masterAddr common.Address, totalReward *big.Int, blockNumber uint64) (map[common.Address]*big.Int, error) { +func GetRewardBalancesRate(chainConfig *params.ChainConfig, foundationWalletAddr common.Address, statedb *state.StateDB, masterAddr common.Address, totalReward *big.Int, blockNumber *big.Int) (map[common.Address]*big.Int, error) { owner := GetCandidatesOwnerBySigner(statedb, masterAddr) balances := make(map[common.Address]*big.Int) rewardMaster := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardMasterPercent)) @@ -445,7 +445,7 @@ func GetRewardBalancesRate(foundationWalletAddr common.Address, statedb *state.S // Get voters capacities. voterCaps := make(map[common.Address]*big.Int) for _, voteAddr := range voters { - if _, ok := voterCaps[voteAddr]; ok && common.TIP2019Block.Uint64() <= blockNumber { + if _, ok := voterCaps[voteAddr]; ok && chainConfig != nil && chainConfig.IsTIP2019(blockNumber) { continue } voterCap := statedb.GetVoterCap(masterAddr, voteAddr) @@ -471,7 +471,7 @@ func GetRewardBalancesRate(foundationWalletAddr common.Address, statedb *state.S foundationReward := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardFoundationPercent)) foundationReward = new(big.Int).Div(foundationReward, new(big.Int).SetInt64(100)) - if blockNumber >= common.TIPUpgradeReward.Uint64() && balances[foundationWalletAddr] != nil { + if chainConfig != nil && chainConfig.IsTIPUpgradeReward(blockNumber) && balances[foundationWalletAddr] != nil { balances[foundationWalletAddr].Add(balances[foundationWalletAddr], foundationReward) } else { balances[foundationWalletAddr] = foundationReward diff --git a/contracts/utils_test.go b/contracts/utils_test.go index 2e3472dedb64..d5cdcdfdc9c1 100644 --- a/contracts/utils_test.go +++ b/contracts/utils_test.go @@ -55,8 +55,19 @@ var ( ) func getCommonBackend() *backends.SimulatedBackend { - genesis := types.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000000)}} - backend := backends.NewXDCSimulatedBackend(genesis, 10000000, params.TestXDPoSMockChainConfig) + legacyConfig := *params.TestXDPoSMockChainConfig + futureForkBlock := big.NewInt(1_000_000_000) + legacyConfig.BerlinBlock = new(big.Int).Set(futureForkBlock) + legacyConfig.LondonBlock = new(big.Int).Set(futureForkBlock) + legacyConfig.MergeBlock = new(big.Int).Set(futureForkBlock) + legacyConfig.ShanghaiBlock = new(big.Int).Set(futureForkBlock) + legacyConfig.Eip1559Block = new(big.Int).Set(futureForkBlock) + legacyConfig.CancunBlock = new(big.Int).Set(futureForkBlock) + legacyConfig.PragueBlock = new(big.Int).Set(futureForkBlock) + legacyConfig.OsakaBlock = new(big.Int).Set(futureForkBlock) + + genesis := types.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000000000000)}} + backend := backends.NewXDCSimulatedBackend(genesis, 10000000, &legacyConfig) backend.Commit() return backend @@ -110,10 +121,13 @@ func TestSendTxSign(t *testing.T) { accounts := []common.Address{acc2Addr, acc3Addr, acc4Addr} keys := []*ecdsa.PrivateKey{acc2Key, acc3Key, acc4Key} backend := getCommonBackend() - signer := types.HomesteadSigner{} + signer := types.LatestSigner(backend.BlockChain().Config()) ctx := context.Background() - transactOpts := bind.NewKeyedTransactor(acc1Key) + transactOpts, err := bind.NewKeyedTransactorWithChainID(acc1Key, backend.BlockChain().Config().ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } blockSignerAddr, blockSigner, err := blocksigner.DeployBlockSigner(transactOpts, backend, big.NewInt(99)) if err != nil { t.Fatalf("Can't get block signer: %v", err) @@ -123,7 +137,7 @@ func TestSendTxSign(t *testing.T) { nonces := make(map[*ecdsa.PrivateKey]int) oldBlocks := make(map[common.Hash]common.Address) - signTx := func(ctx context.Context, backend *backends.SimulatedBackend, signer types.HomesteadSigner, nonces map[*ecdsa.PrivateKey]int, accKey *ecdsa.PrivateKey, blockNumber *big.Int, blockHash common.Hash) *types.Transaction { + signTx := func(ctx context.Context, backend *backends.SimulatedBackend, signer types.Signer, nonces map[*ecdsa.PrivateKey]int, accKey *ecdsa.PrivateKey, blockNumber *big.Int, blockHash common.Hash) *types.Transaction { tx, _ := types.SignTx(CreateTxSign(blockNumber, blockHash, uint64(nonces[accKey]), blockSignerAddr), signer, accKey) backend.SendTransaction(ctx, tx) backend.Commit() diff --git a/contracts/validator/validator_test.go b/contracts/validator/validator_test.go index 3bf9aee364aa..6667c31da7fe 100644 --- a/contracts/validator/validator_test.go +++ b/contracts/validator/validator_test.go @@ -50,8 +50,11 @@ var ( ) func TestValidator(t *testing.T) { - contractBackend := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000, params.TestXDPoSMockChainConfig) - transactOpts := bind.NewKeyedTransactor(key) + contractBackend := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1000))}}, 10000000, params.TestXDPoSMockChainConfig) + transactOpts, err := bind.NewKeyedTransactorWithChainID(key, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } validatorCap := new(big.Int) validatorCap.SetString("50000000000000000000000", 10) @@ -87,14 +90,23 @@ func TestValidator(t *testing.T) { func TestRewardBalance(t *testing.T) { contractBackend := backends.NewXDCSimulatedBackend(types.GenesisAlloc{ - acc1Addr: {Balance: new(big.Int).SetUint64(10000000)}, - acc2Addr: {Balance: new(big.Int).SetUint64(10000000)}, - acc4Addr: {Balance: new(big.Int).SetUint64(10000000)}, + acc1Addr: {Balance: big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1000))}, + acc2Addr: {Balance: big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1000))}, + acc4Addr: {Balance: big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1000))}, }, 42000000, params.TestXDPoSMockChainConfig) - acc1Opts := bind.NewKeyedTransactor(acc1Key) - acc2Opts := bind.NewKeyedTransactor(acc2Key) + acc1Opts, err := bind.NewKeyedTransactorWithChainID(acc1Key, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatalf("can't create acc1 transactor: %v", err) + } + acc2Opts, err := bind.NewKeyedTransactorWithChainID(acc2Key, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatalf("can't create acc2 transactor: %v", err) + } accounts := []*bind.TransactOpts{acc1Opts, acc2Opts} - transactOpts := bind.NewKeyedTransactor(acc1Key) + transactOpts, err := bind.NewKeyedTransactorWithChainID(acc1Key, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatalf("can't create deploy transactor: %v", err) + } // validatorAddr, _, baseValidator, err := contract.DeployXDCValidator(transactOpts, contractBackend, big.NewInt(50000), big.NewInt(99), big.NewInt(100), big.NewInt(100)) validatorCap := new(big.Int) @@ -117,7 +129,10 @@ func TestRewardBalance(t *testing.T) { contractBackend.Commit() // Propose master node acc3Addr. - opts := bind.NewKeyedTransactor(acc4Key) + opts, err := bind.NewKeyedTransactorWithChainID(acc4Key, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatalf("can't create proposer transactor: %v", err) + } opts.Value = new(big.Int).SetUint64(50000) acc4Validator, _ := NewValidator(opts, validatorAddr, contractBackend) acc4Validator.Propose(acc3Addr) @@ -255,7 +270,7 @@ func toyVoteTx(t *testing.T, nonce uint64, amount *big.Int, to, addr common.Addr vote := "6dd7d8ea" // VoteMethod = "0x6dd7d8ea" action := fmt.Sprintf("%s%s%s", vote, "000000000000000000000000", addr.String()[3:]) data := common.Hex2Bytes(action) - gasPrice := big.NewInt(0) + gasPrice := big.NewInt(20_000_000_000) tx := types.NewTransaction(nonce, to, amount, 5000000, gasPrice, data) signedTX, err := types.SignTx(tx, types.FrontierSigner{}, acc4Key) if err != nil { @@ -269,13 +284,16 @@ func TestStatedbUtils(t *testing.T) { voteAmount := new(big.Int) voteAmount.SetString("25000000000000000000000", 10) genesisAlloc := types.GenesisAlloc{ - addr: {Balance: big.NewInt(1000000000)}, + addr: {Balance: big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(1000))}, acc1Addr: {Balance: validatorCap}, acc2Addr: {Balance: validatorCap}, acc4Addr: {Balance: validatorCap}, } contractBackend := backends.NewXDCSimulatedBackend(genesisAlloc, 10000000, params.TestXDPoSMockChainConfig) - transactOpts := bind.NewKeyedTransactor(key) + transactOpts, err := bind.NewKeyedTransactorWithChainID(key, params.TestXDPoSMockChainConfig.ChainID) + if err != nil { + t.Fatalf("can't create transactor: %v", err) + } validatorAddress, _, err := DeployValidator(transactOpts, contractBackend, []common.Address{addr, acc3Addr}, []*big.Int{validatorCap, validatorCap}, addr, nil, nil) if err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index e19ab773a8f9..d73e779514f5 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -241,12 +241,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } } - // Setup the genesis block, commit the provided genesis specification - // to database if the genesis block is not present yet, or load the - // stored one from database. - chainConfig, genesisHash, genesisErr := SetupGenesisBlock(db, genesis) - if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { - return nil, genesisErr + // Write the supplied genesis to the database if it has not been initialized + // yet. The corresponding chain config will be returned, either from the + // provided genesis or from the locally stored configuration if the genesis + // has already been initialized. + chainConfig, genesisHash, compatErr, err := SetupGenesisBlock(db, genesis) + if chainConfig == nil { + return nil, fmt.Errorf("nil chain config returned from SetupGenesisBlock (err=%v)", err) + } + if err != nil { + return nil, err } log.Info(strings.Repeat("-", 153)) for line := range strings.SplitSeq(chainConfig.Description(), "\n") { @@ -294,7 +298,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) bc.processor = NewStateProcessor(chainConfig, bc, engine) - var err error bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped) if err != nil { return nil, err @@ -350,9 +353,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } // Rewind the chain in case of an incompatible config upgrade. - if compat, ok := genesisErr.(*params.ConfigCompatError); ok { - log.Warn("Rewinding chain to upgrade configuration", "err", compat) - bc.SetHead(compat.RewindTo) + if compatErr != nil { + log.Warn("Rewinding chain to upgrade configuration", "err", compatErr) + bc.SetHead(compatErr.RewindTo) rawdb.WriteChainConfig(db, genesisHash, chainConfig) } @@ -1724,6 +1727,7 @@ func (bc *BlockChain) processBlock(block *types.Block, parent *types.Header, sta // Process block using the parent state as reference point. pstart := time.Now() + statedb.SetChainConfig(bc.chainConfig) isTIPXDCXReceiver := bc.Config().IsTIPXDCXReceiver(block.Number()) tradingState, lendingState, err := bc.processTradingAndLendingStates(isTIPXDCXReceiver, block, parent, statedb) if err != nil { @@ -2009,6 +2013,7 @@ func (bc *BlockChain) getResultBlock(block *types.Block, verifiedM2 bool) (*Resu return nil, err } // Process block using the parent state as reference point. + statedb.SetChainConfig(bc.chainConfig) isTIPXDCX := bc.Config().IsTIPXDCX(block.Number()) tradingState, lendingState, err := bc.processTradingAndLendingStates(isTIPXDCX, block, parent, statedb) if err != nil { diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 2554d4d295a3..63ed62eb5e2d 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -289,7 +289,12 @@ func (bc *BlockChain) State() (*state.StateDB, error) { // StateAt returns a new mutable state based on a particular point in time. func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) { - return state.New(root, bc.stateCache) + statedb, err := state.New(root, bc.stateCache) + if err != nil { + return nil, err + } + statedb.SetChainConfig(bc.chainConfig) + return statedb, nil } // Config retrieves the blockchain's chain configuration. diff --git a/core/blockchain_test.go b/core/blockchain_test.go index fa1c0ef67044..336fa2dcf853 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -25,6 +25,7 @@ import ( "time" "github.com/XinFinOrg/XDPoSChain/common" + "github.com/XinFinOrg/XDPoSChain/common/hexutil" "github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/core/rawdb" @@ -959,16 +960,28 @@ func TestEIP155Transition(t *testing.T) { address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) deleteAddr = common.Address{1} + futureFork = big.NewInt(1_000_000_000) gspec = &Genesis{ Config: ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(2), - HomesteadBlock: new(big.Int), + ChainID: big.NewInt(1337), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(2), + HomesteadBlock: new(big.Int), + TIPTRC21FeeBlock: new(big.Int), + BerlinBlock: new(big.Int).Set(futureFork), + LondonBlock: new(big.Int).Set(futureFork), + MergeBlock: new(big.Int).Set(futureFork), + ShanghaiBlock: new(big.Int).Set(futureFork), + Eip1559Block: new(big.Int).Set(futureFork), + CancunBlock: new(big.Int).Set(futureFork), + PragueBlock: new(big.Int).Set(futureFork), + OsakaBlock: new(big.Int).Set(futureFork), }, Alloc: types.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, } ) + setXinFinForksToFuture(gspec.Config, futureFork) + gspec.Config = canonicalizeChainConfig(common.Hash{}, gspec.Config) genDb, blocks, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, func(i int, block *BlockGen) { var ( tx *types.Transaction @@ -1035,11 +1048,14 @@ func TestEIP155Transition(t *testing.T) { // generate an invalid chain id transaction config := ¶ms.ChainConfig{ - ChainID: big.NewInt(2), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(2), - HomesteadBlock: new(big.Int), - } + ChainID: big.NewInt(1338), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(2), + HomesteadBlock: new(big.Int), + TIPTRC21FeeBlock: new(big.Int), + } + setXinFinForksToFuture(config, futureFork) + config = canonicalizeChainConfig(common.Hash{}, config) blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), genDb, 4, func(i int, block *BlockGen) { var ( tx *types.Transaction @@ -1065,20 +1081,32 @@ func TestEIP155Transition(t *testing.T) { func TestEIP161AccountRemoval(t *testing.T) { // Configure and generate a sample block chain var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000) - theAddr = common.Address{1} - gspec = &Genesis{ + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + theAddr = common.Address{1} + futureFork = big.NewInt(1_000_000_000) + gspec = &Genesis{ Config: ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: new(big.Int), - EIP155Block: new(big.Int), - EIP158Block: big.NewInt(2), + ChainID: big.NewInt(1337), + HomesteadBlock: new(big.Int), + EIP155Block: new(big.Int), + EIP158Block: big.NewInt(2), + TIPTRC21FeeBlock: new(big.Int), + BerlinBlock: new(big.Int).Set(futureFork), + LondonBlock: new(big.Int).Set(futureFork), + MergeBlock: new(big.Int).Set(futureFork), + ShanghaiBlock: new(big.Int).Set(futureFork), + Eip1559Block: new(big.Int).Set(futureFork), + CancunBlock: new(big.Int).Set(futureFork), + PragueBlock: new(big.Int).Set(futureFork), + OsakaBlock: new(big.Int).Set(futureFork), }, Alloc: types.GenesisAlloc{address: {Balance: funds}}, } ) + setXinFinForksToFuture(gspec.Config, futureFork) + gspec.Config = canonicalizeChainConfig(common.Hash{}, gspec.Config) _, blocks, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, block *BlockGen) { var ( tx *types.Transaction @@ -1098,15 +1126,16 @@ func TestEIP161AccountRemoval(t *testing.T) { } block.AddTx(tx) }) - // account must exist pre eip 161 + // Under canonicalized custom chain config, zero-value sends do not retain + // empty recipients before the EIP-161 transition point. blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, ethash.NewFaker(), vm.Config{}) defer blockchain.Stop() if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { t.Fatal(err) } - if st, _ := blockchain.State(); !st.Exist(theAddr) { - t.Error("expected account to exist") + if st, _ := blockchain.State(); st.Exist(theAddr) { + t.Error("account should not exist") } // account needs to be deleted post eip 161 @@ -1126,6 +1155,35 @@ func TestEIP161AccountRemoval(t *testing.T) { } } +func setXinFinForksToFuture(cfg *params.ChainConfig, future *big.Int) { + set := func() *big.Int { return new(big.Int).Set(future) } + cfg.TIP2019Block = set() + cfg.TIPSigningBlock = set() + cfg.TIPRandomizeBlock = set() + cfg.TIPIncreaseMasternodesBlock = set() + cfg.DenylistBlock = set() + cfg.TIPNoHalvingMNRewardBlock = set() + cfg.TIPXDCXBlock = set() + cfg.TIPXDCXLendingBlock = set() + cfg.TIPXDCXCancellationFeeBlock = set() + cfg.TIPTRC21FeeBlock = set() + cfg.Gas50xBlock = set() + cfg.BerlinBlock = set() + cfg.LondonBlock = set() + cfg.MergeBlock = set() + cfg.ShanghaiBlock = set() + cfg.TIPXDCXMinerDisableBlock = set() + cfg.TIPXDCXReceiverDisableBlock = set() + cfg.Eip1559Block = set() + cfg.CancunBlock = set() + cfg.PragueBlock = set() + cfg.OsakaBlock = set() + cfg.DynamicGasLimitBlock = set() + cfg.TIPUpgradeRewardBlock = set() + cfg.TIPUpgradePenaltyBlock = set() + cfg.TIPEpochHalvingBlock = set() +} + // This is a regression test (i.e. as weird as it is, don't delete it ever), which // tests that under weird reorg conditions the blockchain and its internal header- // chain return the same latest block/header. @@ -1475,7 +1533,7 @@ func TestEIP2718Transition(t *testing.T) { funds = big.NewInt(1000000000000000) gspec = &Genesis{ Config: ¶ms.ChainConfig{ - ChainID: new(big.Int).SetBytes([]byte("eip1559")), + ChainID: big.NewInt(1337), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: true, @@ -1486,6 +1544,7 @@ func TestEIP2718Transition(t *testing.T) { ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), Eip1559Block: big.NewInt(0), }, Alloc: types.GenesisAlloc{ @@ -1502,6 +1561,7 @@ func TestEIP2718Transition(t *testing.T) { Balance: big.NewInt(50000000000), }, }, + ExtraData: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), } ) // Generate blocks diff --git a/core/chain_makers.go b/core/chain_makers.go index f9a6cb1a69c8..da8627e55add 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -96,8 +96,8 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti b.txs = append(b.txs, tx) b.receipts = append(b.receipts, receipt) if tokenFeeUsed { - fee := common.GetGasFee(b.header.Number.Uint64(), gas) - b.statedb.UpdateTRC21Fee(map[common.Address]*big.Int{*tx.To(): new(big.Int).Sub(feeCapacity[*tx.To()], new(big.Int).SetUint64(gas))}, fee) + fee := common.GetGasFee(b.header.Number.Uint64(), gas, b.config.TIPTRC21FeeBlock, b.config.Gas50xBlock) + b.statedb.UpdateTRC21Fee(map[common.Address]*big.Int{*tx.To(): new(big.Int).Sub(feeCapacity[*tx.To()], fee)}, fee) } } @@ -269,6 +269,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse if err != nil { panic(err) } + statedb.SetChainConfig(config) block, receipt := genblock(i, parent, statedb) blocks[i] = block receipts[i] = receipt diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index dc5bf6428cbe..7f42781e41ef 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -20,6 +20,7 @@ import ( "fmt" "math/big" + "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/types" @@ -39,10 +40,17 @@ func ExampleGenerateChain() { db = rawdb.NewMemoryDatabase() ) // Ensure that key1 has some funds in the genesis block. + futureFork := big.NewInt(1_000_000_000) gspec := &Genesis{ - Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, - Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(1337), + HomesteadBlock: new(big.Int), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, } + setXinFinForksToFuture(gspec.Config, futureFork) + gspec.Config = canonicalizeChainConfig(common.Hash{}, gspec.Config) genesis := gspec.MustCommit(db) // This call generates a chain of 5 blocks. The function runs for @@ -95,5 +103,5 @@ func ExampleGenerateChain() { // last block: #5 // balance of addr1: 989000 // balance of addr2: 10000 - // balance of addr3: 19687500000000001000 + // balance of addr3: 11812500000000001000 } diff --git a/core/genesis.go b/core/genesis.go index 797295f230a4..7f3e4fe12fb8 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -39,7 +39,10 @@ import ( //go:generate go run github.com/fjl/gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go -var errGenesisNoConfig = errors.New("genesis has no chain configuration") +var ( + errGenesisNoConfig = errors.New("genesis has no chain configuration") + jsonMarshal = json.Marshal +) // Deprecated: use types.Account instead. type GenesisAccount = types.Account @@ -68,6 +71,19 @@ type Genesis struct { BaseFee *big.Int `json:"baseFeePerGas"` } +// copy copies the genesis. +func (g *Genesis) copy() *Genesis { + if g != nil { + cpy := *g + if g.Config != nil { + conf := *g.Config + cpy.Config = &conf + } + return &cpy + } + return nil +} + func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) { blob := rawdb.ReadGenesisStateSpec(db, blockhash) if len(blob) != 0 { @@ -179,7 +195,19 @@ func (e *GenesisMismatchError) Error() string { return fmt.Sprintf("database contains incompatible genesis (have %x, new %x)", e.Stored, e.New) } -// SetupGenesisBlock writes or updates the genesis block in db. +// canonicalizeChainConfig resolves built-in hashes to their bundled configs. +// For non built-in networks it clones and backfills missing fields from +// LocalnetChainConfig. +func canonicalizeChainConfig(hash common.Hash, cfg *params.ChainConfig) *params.ChainConfig { + builtin := params.GetBuiltInChainConfigByHash(hash) + if builtin != nil { + return builtin + } + return cfg.BackfillMissingFields() +} + +// SetupGenesisBlock writes or updates the genesis block in db, +// returning the resolved chain config and genesis hash. // The block that will be used is: // // genesis == nil genesis != nil @@ -187,114 +215,158 @@ func (e *GenesisMismatchError) Error() string { // db has no genesis | main-net default | genesis // db has genesis | from DB | genesis (if compatible) // -// The stored chain configuration will be updated if it is compatible (i.e. does not -// specify a fork block below the local head block). In case of a conflict, the -// error is a *params.ConfigCompatError and the new, unwritten config is returned. +// Rules: +// - For built-in networks: always returns the hardcoded in-memory config. +// - For custom networks: the provided genesis config is backfilled from +// LocalnetChainConfig before write and validation. +// - For stored custom configs: read-time backfill is also applied to keep +// compatibility when new ChainConfig fields are introduced. // -// The returned chain configuration is never nil. -func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { - if genesis != nil && genesis.Config == nil { - return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig +// Returns: +// - chainConfig: the resolved config (never nil on success) +// - genesisHash: the canonical genesis block hash +// - compatErr: compatibility error if config upgrade/downgrade is needed +// - err: other errors (e.g. missing config, DB errors) +func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (chainConfig *params.ChainConfig, genesisHash common.Hash, compatErr *params.ConfigCompatError, err error) { + defer func() { + if chainConfig == nil { + log.Info("Resolved chain config", "cfg", "nil", "hash", genesisHash.Hex(), "compatErr", compatErr, "err", err) + } else { + name := chainConfig.Name + if name == "" { + name = "unknown" + } + log.Info("Resolved chain config", "cfg", name, "hash", genesisHash.Hex(), "chainId", chainConfig.ChainID, "compatErr", compatErr, "err", err) + } + }() + + // Copy the genesis, so we can operate on a copy. + genesis = genesis.copy() + + var originalGenesisHash common.Hash + if genesis != nil { + // Sanitize the supplied genesis, ensuring it has the associated chain + // config attached. + if genesis.Config == nil { + return nil, common.Hash{}, nil, errGenesisNoConfig + } + + // Normalize caller-provided config once at entry so all later comparisons, + // compatibility checks and persistence operate on canonical form. + originalGenesisHash = genesis.ToBlock().Hash() + genesis.Config = canonicalizeChainConfig(originalGenesisHash, genesis.Config) } - // Just commit the new block if there is no stored genesis block. - stored := rawdb.ReadCanonicalHash(db, 0) - if (stored == common.Hash{}) { + // Commit the genesis if the database is empty + ghash := rawdb.ReadCanonicalHash(db, 0) + if (ghash == common.Hash{}) { if genesis == nil { - log.Info("[SetupGenesisBlock] Writing default main-net genesis block") + log.Info("Writing default main-net genesis block") genesis = DefaultGenesisBlock() } else { - log.Info("[SetupGenesisBlock] Writing custom genesis block") + log.Info("Writing custom genesis block") } block, err := genesis.Commit(db) if err != nil { - return genesis.Config, common.Hash{}, err + return nil, common.Hash{}, nil, err } - log.Info("[SetupGenesisBlock] genesis blockhash", "hash", block.Hash().Hex()) - return genesis.Config, block.Hash(), err + return genesis.Config, block.Hash(), nil, nil } - // We have the genesis block in database (perhaps in ancient database) - // but the corresponding state is missing. - header := rawdb.ReadHeader(db, stored, 0) - if header == nil { - log.Info("[SetupGenesisBlock] missing genesis header", "stored hash", stored.Hex()) - cfg := genesis.configOrDefault(stored) - return cfg, stored, fmt.Errorf("missing genesis header for hash: %s", stored.Hex()) + // Commit the genesis if the genesis block exists in the ancient database + // but the key-value database is empty without initializing the genesis + // fields. This scenario can occur when the node is created from scratch + // with an existing ancient store. + storedCfg, readErr := rawdb.ReadChainConfig(db, ghash) + if readErr != nil && !errors.Is(readErr, rawdb.ErrChainConfigNotFound) { + return nil, common.Hash{}, nil, readErr } - if _, err := state.New(header.Root, state.NewDatabaseWithConfig(db, nil)); err != nil { + if storedCfg == nil { + if header := rawdb.ReadHeader(db, ghash, 0); header == nil { + return nil, ghash, nil, fmt.Errorf("missing genesis header for hash: %s", ghash.Hex()) + } + // Ensure the stored genesis block matches with the given genesis. Private + // networks must explicitly specify the genesis in the config file, mainnet + // genesis will be used as default and the initialization will always fail. if genesis == nil { - log.Info("[SetupGenesisBlock] missing genesis state, use default genesis block to recover", "hash", stored.Hex()) + log.Info("Writing default main-net genesis block") genesis = DefaultGenesisBlock() + } else { + log.Info("Writing custom genesis block") } - // Ensure the stored genesis matches with the given one. - hash := genesis.ToBlock().Hash() - log.Info("[SetupGenesisBlock] doublecheck genesis block", "storedHash", stored.Hex(), "genesisHash", hash.Hex()) - if hash != stored { - return genesis.Config, hash, &GenesisMismatchError{stored, hash} + if hash := genesis.ToBlock().Hash(); hash != ghash { + return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} } block, err := genesis.Commit(db) if err != nil { - return genesis.Config, hash, err + return nil, common.Hash{}, nil, err } - return genesis.Config, block.Hash(), nil + return genesis.Config, block.Hash(), nil, nil } + originalStoredCfg := storedCfg + storedCfg = canonicalizeChainConfig(ghash, storedCfg) - // Check whether the genesis block is already written. + // The genesis block has already been committed previously. Verify that the + // provided genesis with chain overrides matches the existing one, and update + // the stored chain config if necessary. if genesis != nil { - hash := genesis.ToBlock().Hash() - log.Info("[SetupGenesisBlock] genesis != nil", "storedHash", stored.Hex(), "genesisHash", hash.Hex()) - if hash != stored { - return genesis.Config, hash, &GenesisMismatchError{stored, hash} + if hash := genesis.ToBlock().Hash(); hash != ghash && originalGenesisHash != ghash { + return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} } } - // Get the existing chain configuration. - newcfg := genesis.configOrDefault(stored) - storedcfg, err := rawdb.ReadChainConfig(db, stored) - if err != nil { - return nil, common.Hash{}, err + // Check config compatibility and write the config. Compatibility errors + // are returned to the caller unless we're already at block zero. + headHeaderHash := rawdb.ReadHeadHeaderHash(db) + if headHeaderHash != (common.Hash{}) && rawdb.ReadHeaderNumber(db, headHeaderHash) == nil { + return storedCfg, ghash, nil, errors.New("missing block number for head header hash") } - if storedcfg == nil { - log.Warn("Found genesis block without chain config") - rawdb.WriteChainConfig(db, stored, newcfg) - return newcfg, stored, nil + head := rawdb.ReadHeadHeader(db) + if head == nil { + return nil, common.Hash{}, nil, errors.New("missing head header") } + newCfg := genesis.chainConfigOrDefault(ghash, storedCfg) - // Special case: don't change the existing config of a non-xinfin chain if no new - // config is supplied. These chains would get AllProtocolChanges (and a compat error) - // if we just continued here. - if genesis == nil && newcfg == params.AllEthashProtocolChanges { - return storedcfg, stored, nil + // Sanity-check the new configuration. + if err := newCfg.CheckConfigForkOrder(); err != nil { + return nil, common.Hash{}, nil, err } - // Check config compatibility and write the config. Compatibility errors - // are returned to the caller unless we're already at block zero. - height := rawdb.ReadHeaderNumber(db, rawdb.ReadHeadHeaderHash(db)) - if height == nil { - return newcfg, stored, errors.New("missing block number for head header hash") - } - compatErr := storedcfg.CheckCompatible(newcfg, *height) - if compatErr != nil && *height != 0 && compatErr.RewindTo != 0 { - return newcfg, stored, compatErr + // TODO(rjl493456442) better to define the comparator of chain config + // and short circuit if the chain config is not changed. + compatErr = storedCfg.CheckCompatible(newCfg, head.Number.Uint64()) + if compatErr != nil && (head.Number.Uint64() != 0 && compatErr.RewindTo != 0) { + return newCfg, ghash, compatErr, nil } - // Don't overwrite if the old is identical to the new - storedData, err := json.Marshal(storedcfg) + + // Don't overwrite if the old is identical to the new. It's useful + // for the scenarios that database is opened in the read-only mode. + storedData, err := jsonMarshal(originalStoredCfg) if err != nil { - return newcfg, stored, fmt.Errorf("failed to marshal stored chain config: %w", err) + return newCfg, ghash, nil, fmt.Errorf("failed to marshal stored chain config: %w", err) } - newData, err := json.Marshal(newcfg) + newData, err := jsonMarshal(newCfg) if err != nil { - return newcfg, stored, fmt.Errorf("failed to marshal new chain config: %w", err) + return newCfg, ghash, nil, fmt.Errorf("failed to marshal new chain config: %w", err) } if !bytes.Equal(storedData, newData) { - rawdb.WriteChainConfig(db, stored, newcfg) + rawdb.WriteChainConfig(db, ghash, newCfg) } - return newcfg, stored, nil + + return newCfg, ghash, nil, nil } -// LoadChainConfig loads the stored chain config if it is already present in -// database, otherwise, return the config in the provided genesis specification. +// LoadChainConfig loads the stored chain config from the database, or falls back to the provided genesis config. +// - For built-in networks: always returns the hardcoded in-memory config. +// - For custom networks: applies LocalnetChainConfig backfill to both +// provided genesis configs and stored configs from DB. +// - Read-time backfill is intentionally kept so newly added ChainConfig +// fields stay compatible with historical persisted configs. +// +// Returns: +// - cfg: the resolved config (never nil on success) +// - ghash: the canonical genesis block hash +// - err: error if config is missing or invalid func LoadChainConfig(db ethdb.Database, genesis *Genesis) (cfg *params.ChainConfig, ghash common.Hash, err error) { // Load the stored chain config from the database. It can be nil // in case the database is empty. Notably, we only care about the @@ -302,51 +374,62 @@ func LoadChainConfig(db ethdb.Database, genesis *Genesis) (cfg *params.ChainConf stored := rawdb.ReadCanonicalHash(db, 0) if stored != (common.Hash{}) { storedcfg, err := rawdb.ReadChainConfig(db, stored) - if err != nil { + if err != nil && !errors.Is(err, rawdb.ErrChainConfigNotFound) { return nil, common.Hash{}, err } if storedcfg != nil { - return storedcfg, stored, nil + cfg := canonicalizeChainConfig(stored, storedcfg) + err := cfg.CheckConfigForkOrder() + if err != nil { + return nil, stored, err + } + return cfg, stored, err } } + // Load the config from the provided genesis specification if genesis != nil { // Reject invalid genesis spec without valid chain config if genesis.Config == nil { return nil, common.Hash{}, errGenesisNoConfig } + originalHash := genesis.ToBlock().Hash() + genesis.Config = canonicalizeChainConfig(originalHash, genesis.Config) + err := genesis.Config.CheckConfigForkOrder() + if err != nil { + return nil, common.Hash{}, err + } // If the canonical genesis header is present, but the chain // config is missing(initialize the empty leveldb with an // external ancient chain segment), ensure the provided genesis // is matched. ghash := genesis.ToBlock().Hash() - if stored != (common.Hash{}) && ghash != stored { + if stored != (common.Hash{}) && ghash != stored && originalHash != stored { return nil, ghash, &GenesisMismatchError{stored, ghash} } return genesis.Config, ghash, nil } + // There is no stored chain config and no new config provided, // In this case the default chain config(mainnet) will be used return params.XDCMainnetChainConfig, params.MainnetGenesisHash, nil } -func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { +// chainConfigOrDefault retrieves the attached chain configuration. If the genesis +// object is null, it returns the default chain configuration based on the given +// genesis hash, or the locally stored config if it's not a pre-defined network. +func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainConfig) *params.ChainConfig { switch { case g != nil: - log.Info("[configOrDefault] load orignal config", "hash", ghash) return g.Config case ghash == params.MainnetGenesisHash: - log.Info("[configOrDefault] load mainnetconfig") return params.XDCMainnetChainConfig case ghash == params.TestnetGenesisHash: - log.Info("[configOrDefault] load TestnetChainConfig") return params.TestnetChainConfig case ghash == params.DevnetGenesisHash: - log.Info("[configOrDefault] load DevnetChainConfig") return params.DevnetChainConfig default: - log.Info("[configOrDefault] load AllEthashProtocolChanges", "hash", ghash) - return params.AllEthashProtocolChanges + return stored } } @@ -376,9 +459,8 @@ func (g *Genesis) ToBlock() *types.Block { if g.Difficulty == nil { head.Difficulty = params.GenesisDifficulty } - // Notice: Eip1559Block affects the block hash, we must set: - // 1. g.Config.Eip1559Block - // 2. or common.Eip1559Block + // Notice: Eip1559Block affects the block hash, so g.Config.Eip1559Block + // must be set in genesis chain config when EIP-1559 should be active. if g.Config != nil && g.Config.IsEIP1559(common.Big0) { if g.BaseFee != nil { head.BaseFee = g.BaseFee @@ -400,6 +482,9 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { if config == nil { return nil, errors.New("invalid genesis without chain config") } + if err := config.CheckConfigForkOrder(); err != nil { + return nil, err + } if config.XDPoS != nil && len(g.ExtraData) < 32+crypto.SignatureLength { return nil, errors.New("can't start XDPoS chain without signers") } diff --git a/core/genesis_test.go b/core/genesis_test.go index c8a37e3ff43e..ed4a1f7aa8e1 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -17,10 +17,14 @@ package core import ( + "bytes" + "encoding/json" "errors" "fmt" "math/big" "reflect" + "slices" + "strings" "testing" "github.com/XinFinOrg/XDPoSChain/common" @@ -28,11 +32,195 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/vm" + "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/params" "github.com/davecgh/go-spew/spew" ) +func chainConfigSemanticallyEqual(a, b *params.ChainConfig) bool { + if a == nil || b == nil { + return a == b + } + va := reflect.ValueOf(a).Elem() + vb := reflect.ValueOf(b).Elem() + fields := []string{"ChainID", "TIPTRC21FeeBlock", "XDPoS"} + // Add non-nil fields from b (only call IsNil on types that support it) + nilKinds := map[reflect.Kind]bool{ + reflect.Pointer: true, reflect.Slice: true, reflect.Map: true, reflect.Chan: true, reflect.Func: true, reflect.Interface: true, + } + typeOfCfg := va.Type() + for i := 0; i < vb.NumField(); i++ { + fname := typeOfCfg.Field(i).Name + if slices.Contains(fields, fname) { + continue + } + fieldVal := vb.Field(i) + if nilKinds[fieldVal.Kind()] && !fieldVal.IsNil() { + fields = append(fields, fname) + } + } + for _, fname := range fields { + fa := va.FieldByName(fname) + fb := vb.FieldByName(fname) + if !fa.IsValid() || !fb.IsValid() { + return false + } + // For *big.Int pointers + if fa.Type().String() == "*big.Int" { + if fa.Kind() == reflect.Ptr && fb.Kind() == reflect.Ptr { + if (fa.IsNil() && !fb.IsNil()) || (!fa.IsNil() && fb.IsNil()) { + return false + } + if !fa.IsNil() && fa.Interface().(*big.Int).Cmp(fb.Interface().(*big.Int)) != 0 { + return false + } + continue + } + } + // For XDPoS field + if fname == "XDPoS" { + if !params.XDPoSConfigEqual(fa.Interface().(*params.XDPoSConfig), fb.Interface().(*params.XDPoSConfig)) { + return false + } + continue + } + // Only call IsNil on types that support it + nilKinds := map[reflect.Kind]bool{ + reflect.Ptr: true, reflect.Slice: true, reflect.Map: true, reflect.Chan: true, reflect.Func: true, reflect.Interface: true, + } + if !nilKinds[fa.Kind()] { + if !reflect.DeepEqual(fa.Interface(), fb.Interface()) { + return false + } + continue + } + // Only proceed if both sides support IsNil + if fa.IsNil() != fb.IsNil() { + return false + } + if fa.IsNil() && fb.IsNil() { + continue + } + if !reflect.DeepEqual(fa.Interface(), fb.Interface()) { + return false + } + } + return true +} + +// jsonKeyToForkFieldName maps a migrated fork JSON key to the matching +// ChainConfig struct field name used by reflection-based test and logging helpers. +func jsonKeyToForkFieldName(jsonKey string) string { + if strings.HasPrefix(jsonKey, "tip") { + return "TIP" + jsonKey[len("tip"):] + } + if jsonKey == "" { + return "" + } + return strings.ToUpper(jsonKey[:1]) + jsonKey[1:] +} + +func assertMigratedForkFieldsEqual(t *testing.T, got, want *params.ChainConfig) { + t.Helper() + vgot := reflect.ValueOf(got).Elem() + vwant := reflect.ValueOf(want).Elem() + for _, key := range params.MigratedForkFieldJSONKeys() { + name := jsonKeyToForkFieldName(key) + gotField := vgot.FieldByName(name) + wantField := vwant.FieldByName(name) + if !gotField.IsValid() || !wantField.IsValid() { + t.Fatalf("missing field %s on ChainConfig", name) + } + if wantField.IsNil() { + if !gotField.IsNil() { + t.Fatalf("unexpected %s: have %v want nil", name, gotField.Interface()) + } + continue + } + if gotField.IsNil() { + t.Fatalf("unexpected %s: have nil want %v", name, wantField.Interface()) + } + gotBig := gotField.Interface().(*big.Int) + wantBig := wantField.Interface().(*big.Int) + if gotBig.Cmp(wantBig) != 0 { + t.Fatalf("unexpected %s: have %v want %v", name, gotBig, wantBig) + } + } +} + +func assertMigratedForkFieldsNil(t *testing.T, got *params.ChainConfig) { + t.Helper() + vgot := reflect.ValueOf(got).Elem() + for _, key := range params.MigratedForkFieldJSONKeys() { + name := jsonKeyToForkFieldName(key) + gotField := vgot.FieldByName(name) + if !gotField.IsValid() { + t.Fatalf("missing field %s on ChainConfig", name) + } + if !gotField.IsNil() { + t.Fatalf("unexpected %s for custom chain: have %v want nil", name, gotField.Interface()) + } + } +} + +func removeXDPoSMaxMasternodesV2FromRawConfig(raw []byte) ([]byte, error) { + var root map[string]json.RawMessage + if err := json.Unmarshal(raw, &root); err != nil { + return nil, err + } + xdposRaw, ok := root["XDPoS"] + if !ok || len(xdposRaw) == 0 || string(bytes.TrimSpace(xdposRaw)) == "null" { + return raw, nil + } + var xdposFields map[string]json.RawMessage + if err := json.Unmarshal(xdposRaw, &xdposFields); err != nil { + return nil, err + } + delete(xdposFields, "maxMasternodesV2") + updatedXDPoS, err := json.Marshal(xdposFields) + if err != nil { + return nil, err + } + root["XDPoS"] = updatedXDPoS + return json.Marshal(root) +} + +func removeTopLevelFieldFromRawConfig(raw []byte, field string) ([]byte, error) { + var root map[string]json.RawMessage + if err := json.Unmarshal(raw, &root); err != nil { + return nil, err + } + delete(root, field) + return json.Marshal(root) +} + +type failingConfigReadDB struct { + ethdb.Database + targetKey []byte + getErr error + hasResult bool + hasErr error +} + +func (db *failingConfigReadDB) Has(key []byte) (bool, error) { + if bytes.Equal(key, db.targetKey) { + return db.hasResult, db.hasErr + } + return db.Database.Has(key) +} + +func (db *failingConfigReadDB) Get(key []byte) ([]byte, error) { + if bytes.Equal(key, db.targetKey) { + return nil, db.getErr + } + return db.Database.Get(key) +} + +func testConfigKey(hash common.Hash) []byte { + return append([]byte("ethereum-config-"), hash.Bytes()...) +} + func TestDefaultGenesisBlock(t *testing.T) { block := DefaultGenesisBlock().ToBlock() if block.Hash() != params.MainnetGenesisHash { @@ -44,36 +232,829 @@ func TestDefaultGenesisBlock(t *testing.T) { } } +func TestSetupGenesisNormalizesLocalnetChainConfig(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: params.LocalnetChainConfig.ChainID, + TIPTRC21FeeBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(9), + BerlinBlock: big.NewInt(12), + CancunBlock: big.NewInt(34), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + inputCfg := genesis.Config + + cfg, _, _, err := SetupGenesisBlock(db, genesis) + if err != nil { + t.Fatalf("SetupGenesisBlock failed: %v", err) + } + if cfg == params.LocalnetChainConfig { + t.Fatal("unexpected localnet singleton reuse") + } + if cfg == inputCfg { + t.Fatal("expected canonicalized config to be a copy") + } + if cfg.ChainID == params.LocalnetChainConfig.ChainID { + t.Fatal("expected canonicalized chain id to be deep-copied") + } + if cfg.ConstantinopleBlock == nil || cfg.ConstantinopleBlock.Cmp(big.NewInt(9)) != 0 { + t.Fatalf("unexpected preserved Constantinople block: have %v want 9", cfg.ConstantinopleBlock) + } + if cfg.BerlinBlock == nil || cfg.BerlinBlock.Cmp(big.NewInt(12)) != 0 { + t.Fatalf("unexpected preserved Berlin block: have %v want 12", cfg.BerlinBlock) + } + if cfg.CancunBlock == nil || cfg.CancunBlock.Cmp(big.NewInt(34)) != 0 { + t.Fatalf("unexpected preserved Cancun block: have %v want 34", cfg.CancunBlock) + } + if cfg.Ethash == nil { + t.Fatal("expected non-whitelisted fields to be preserved") + } + if cfg.PragueBlock != nil || cfg.DynamicGasLimitBlock != nil || cfg.TIPUpgradeRewardBlock != nil { + t.Fatalf("unexpected localnet whitelist fields: Prague=%v DynamicGasLimit=%v TIPUpgradeReward=%v", cfg.PragueBlock, cfg.DynamicGasLimitBlock, cfg.TIPUpgradeRewardBlock) + } + if cfg.LondonBlock == nil || cfg.LondonBlock.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("unexpected localnet London block: have %v want 0", cfg.LondonBlock) + } + + storedCfg, _, err := LoadChainConfig(db, genesis) + if err != nil { + t.Fatalf("LoadChainConfig failed: %v", err) + } + if storedCfg == nil { + t.Fatal("expected stored config") + } + if storedCfg.ChainID == nil || storedCfg.ChainID.Cmp(big.NewInt(5151)) != 0 { + t.Fatalf("unexpected stored chain id: have %v want 5151", storedCfg.ChainID) + } + if storedCfg.ConstantinopleBlock == nil || storedCfg.ConstantinopleBlock.Cmp(big.NewInt(9)) != 0 { + t.Fatalf("unexpected stored Constantinople block: have %v want 9", storedCfg.ConstantinopleBlock) + } + if storedCfg.BerlinBlock == nil || storedCfg.BerlinBlock.Cmp(big.NewInt(12)) != 0 { + t.Fatalf("unexpected stored Berlin block: have %v want 12", storedCfg.BerlinBlock) + } + if storedCfg.CancunBlock == nil || storedCfg.CancunBlock.Cmp(big.NewInt(34)) != 0 { + t.Fatalf("unexpected stored Cancun block: have %v want 34", storedCfg.CancunBlock) + } + if storedCfg.LondonBlock == nil || storedCfg.LondonBlock.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("unexpected stored London block: have %v want 0", storedCfg.LondonBlock) + } +} + +func TestCloneChainConfigDeepCopiesMigratedForkBlocks(t *testing.T) { + original := ¶ms.ChainConfig{ + ChainID: big.NewInt(5151), + TIP2019Block: big.NewInt(10), + TIPSigningBlock: big.NewInt(20), + TIPRandomizeBlock: big.NewInt(30), + TIPIncreaseMasternodesBlock: big.NewInt(35), + DenylistBlock: big.NewInt(40), + TIPNoHalvingMNRewardBlock: big.NewInt(45), + TIPXDCXBlock: big.NewInt(50), + TIPXDCXLendingBlock: big.NewInt(60), + TIPXDCXCancellationFeeBlock: big.NewInt(70), + TIPTRC21FeeBlock: big.NewInt(75), + BerlinBlock: big.NewInt(80), + LondonBlock: big.NewInt(90), + MergeBlock: big.NewInt(100), + ShanghaiBlock: big.NewInt(110), + TIPXDCXMinerDisableBlock: big.NewInt(120), + TIPXDCXReceiverDisableBlock: big.NewInt(130), + Eip1559Block: big.NewInt(140), + CancunBlock: big.NewInt(150), + PragueBlock: big.NewInt(160), + OsakaBlock: big.NewInt(170), + DynamicGasLimitBlock: big.NewInt(180), + TIPUpgradeRewardBlock: big.NewInt(190), + TIPUpgradePenaltyBlock: big.NewInt(200), + TIPEpochHalvingBlock: big.NewInt(210), + } + clone := original.Clone() + if clone == nil { + t.Fatal("expected clone") + } + orig := reflect.ValueOf(original).Elem() + cloned := reflect.ValueOf(clone).Elem() + for _, key := range params.MigratedForkFieldJSONKeys() { + name := jsonKeyToForkFieldName(key) + origField := orig.FieldByName(name) + cloneField := cloned.FieldByName(name) + if origField.IsNil() || cloneField.IsNil() { + t.Fatalf("field %s must be non-nil in clone test", name) + } + origBig := origField.Interface().(*big.Int) + cloneBig := cloneField.Interface().(*big.Int) + if origBig == cloneBig { + t.Fatalf("expected %s to be deep-copied", name) + } + want := new(big.Int).Set(origBig) + cloneBig.Add(cloneBig, big.NewInt(999)) + if origBig.Cmp(want) != 0 { + t.Fatalf("original %s mutated: have %v want %v", name, origBig, want) + } + } +} + +func TestSetupGenesisBackfillsMissingXDPoSMaxMasternodesV2ForBuiltInNetworks(t *testing.T) { + db := rawdb.NewMemoryDatabase() + DefaultGenesisBlock().MustCommit(db) + + stored := params.MainnetGenesisHash + rawCfg, err := rawdb.ReadChainConfigJSON(db, stored) + if err != nil { + t.Fatalf("failed to read raw chain config: %v", err) + } + updatedRawCfg, err := removeXDPoSMaxMasternodesV2FromRawConfig(rawCfg) + if err != nil { + t.Fatalf("failed to remove XDPoS.maxMasternodesV2 from raw config: %v", err) + } + if err := db.Put(testConfigKey(stored), updatedRawCfg); err != nil { + t.Fatalf("failed to write modified raw chain config: %v", err) + } + + cfg, _, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("expected nil, got %v", err) + } + if cfg != nil && cfg.XDPoS != nil && cfg.XDPoS.MaxMasternodesV2 != params.XDCMainnetChainConfig.XDPoS.MaxMasternodesV2 { + t.Fatalf("expected MaxMasternodesV2 to be %d when missing, got %d", params.XDCMainnetChainConfig.XDPoS.MaxMasternodesV2, cfg.XDPoS.MaxMasternodesV2) + } + + persistedCfg, err := rawdb.ReadChainConfig(db, stored) + if err != nil { + t.Fatalf("failed to read persisted config: %v", err) + } + if persistedCfg == nil || persistedCfg.XDPoS == nil { + t.Fatalf("expected persisted XDPoS config, have %v", persistedCfg) + } + if persistedCfg.XDPoS.MaxMasternodesV2 != params.XDCMainnetChainConfig.XDPoS.MaxMasternodesV2 { + t.Fatalf("unexpected persisted MaxMasternodesV2: have %d want %d", persistedCfg.XDPoS.MaxMasternodesV2, params.XDCMainnetChainConfig.XDPoS.MaxMasternodesV2) + } +} + +func TestSetupGenesisBackfillsMissingXDPoSMaxMasternodesV2ForDevnet(t *testing.T) { + db := rawdb.NewMemoryDatabase() + DefaultDevnetGenesisBlock().MustCommit(db) + + stored := params.DevnetGenesisHash + rawCfg, err := rawdb.ReadChainConfigJSON(db, stored) + if err != nil { + t.Fatalf("failed to read raw chain config: %v", err) + } + updatedRawCfg, err := removeXDPoSMaxMasternodesV2FromRawConfig(rawCfg) + if err != nil { + t.Fatalf("failed to remove XDPoS.maxMasternodesV2 from raw config: %v", err) + } + if err := db.Put(testConfigKey(stored), updatedRawCfg); err != nil { + t.Fatalf("failed to write modified raw chain config: %v", err) + } + + cfg, _, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("expected nil, got %v", err) + } + if cfg != nil && cfg.XDPoS != nil && cfg.XDPoS.MaxMasternodesV2 != params.DevnetChainConfig.XDPoS.MaxMasternodesV2 { + t.Fatalf("expected MaxMasternodesV2 to be %d when missing, got %d", params.DevnetChainConfig.XDPoS.MaxMasternodesV2, cfg.XDPoS.MaxMasternodesV2) + } +} + +func TestSetupGenesisFillsLegacyCustomChainMissingXDPoSMaxMasternodesV2InMemory(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesisCfg := params.XDCMainnetChainConfig.Clone() + genesisCfg.ChainID = big.NewInt(9798) + genesisCfg.XDPoS = genesisCfg.XDPoS.Clone() + genesisCfg.XDPoS.MaxMasternodesV2 = 0 + genesis := &Genesis{ + Config: genesisCfg, + ExtraData: make([]byte, 32+crypto.SignatureLength), + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + _, err := genesis.Commit(db) + if !errors.Is(err, params.ErrMissingForkSwitch) { + t.Fatalf("expected ErrMissingForkSwitch from Commit, got %v", err) + } +} + +func TestSetupGenesisBackfillsMissingChainIDForNonBuiltInChain(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(4444), + TIPTRC21FeeBlock: big.NewInt(0), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + block := genesis.MustCommit(db) + + rawCfg, err := rawdb.ReadChainConfigJSON(db, block.Hash()) + if err != nil { + t.Fatalf("failed to read raw chain config: %v", err) + } + updatedRawCfg, err := removeTopLevelFieldFromRawConfig(rawCfg, "chainId") + if err != nil { + t.Fatalf("failed to remove chainId from raw config: %v", err) + } + if err := db.Put(testConfigKey(block.Hash()), updatedRawCfg); err != nil { + t.Fatalf("failed to write modified raw chain config: %v", err) + } + + resolvedCfg, hash, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("SetupGenesisBlock failed: %v", err) + } + if hash != block.Hash() { + t.Fatalf("unexpected genesis hash: have %s want %s", hash.Hex(), block.Hash().Hex()) + } + if resolvedCfg == nil || resolvedCfg.ChainID == nil { + t.Fatalf("expected resolved ChainID, have %v", resolvedCfg) + } + if resolvedCfg.ChainID.Cmp(params.LocalnetChainConfig.ChainID) != 0 { + t.Fatalf("unexpected ChainID: have %v want %v", resolvedCfg.ChainID, params.LocalnetChainConfig.ChainID) + } +} + +func TestSetupGenesisBackfillsNilXDPoSForNonBuiltInChain(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(5555), + TIPTRC21FeeBlock: big.NewInt(0), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + block := genesis.MustCommit(db) + + resolvedCfg, hash, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("SetupGenesisBlock failed: %v", err) + } + if hash != block.Hash() { + t.Fatalf("unexpected genesis hash: have %s want %s", hash.Hex(), block.Hash().Hex()) + } + if resolvedCfg != nil && resolvedCfg.XDPoS != nil { + t.Fatalf("expected resolvedCfg: nil, have %v", resolvedCfg) + } +} + +func TestSetupGenesisBackfillsCustomGenesisFromLocalnetOnWrite(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(999001), + TIPTRC21FeeBlock: big.NewInt(0), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + + cfg, _, _, err := SetupGenesisBlock(db, genesis) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if cfg == nil { + t.Fatal("expected resolved config") + } + if cfg == params.XDCMainnetChainConfig || cfg == params.TestnetChainConfig || cfg == params.DevnetChainConfig { + t.Fatalf("expected custom config classification, got built-in pointer: %v", cfg) + } + if cfg.ChainID == nil || cfg.ChainID.Cmp(big.NewInt(999001)) != 0 { + t.Fatalf("unexpected ChainID: have %v want 999001", cfg.ChainID) + } + if cfg.TIP2019Block == nil || cfg.TIP2019Block.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("expected TIP2019Block to be backfilled to 0, have %v", cfg.TIP2019Block) + } + if cfg.XDPoS != nil { + t.Fatalf("expected no XDPoS backfill for explicit genesis, have %v", cfg.XDPoS) + } +} + +func TestSetupGenesisTreatsStoredCustomGenesisWithBuiltInChainIDAsLocalnet(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: new(big.Int).Set(params.XDCMainnetChainConfig.ChainID), + TIPTRC21FeeBlock: big.NewInt(0), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + genesis.MustCommit(db) + + cfg, hash, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if hash != genesis.ToBlock().Hash() { + t.Fatalf("unexpected hash: have %s want %s", hash.Hex(), genesis.ToBlock().Hash().Hex()) + } + // Only check ChainID and XDPoS.MaxMasternodesV2, do not require all migrated fork fields to be backfilled. + if cfg.ChainID.Cmp(params.XDCMainnetChainConfig.ChainID) != 0 { + t.Fatalf("unexpected ChainID: have %v want %v", cfg.ChainID, params.XDCMainnetChainConfig.ChainID) + } + if cfg.XDPoS != nil && cfg.XDPoS.MaxMasternodesV2 != params.LocalnetChainConfig.XDPoS.MaxMasternodesV2 { + t.Fatalf("unexpected MaxMasternodesV2: have %v want %v", cfg.XDPoS, params.LocalnetChainConfig.XDPoS.MaxMasternodesV2) + } +} + +func TestSetupGenesisAllowsCustomChainWithIntentionallyNilOsakaBlock(t *testing.T) { + db := rawdb.NewMemoryDatabase() + cfg := params.XDCMainnetChainConfig.Clone() + cfg.ChainID = big.NewInt(7778) + cfg.XDPoS = nil + cfg.Ethash = new(params.EthashConfig) + cfg.OsakaBlock = nil + + genesis := &Genesis{ + Config: cfg, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + block := genesis.MustCommit(db) + + resolvedCfg, hash, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("SetupGenesisBlock failed: %v", err) + } + if hash != block.Hash() { + t.Fatalf("unexpected genesis hash: have %s want %s", hash.Hex(), block.Hash().Hex()) + } + if resolvedCfg == nil { + t.Fatal("expected resolved config") + } + if resolvedCfg.OsakaBlock != nil { + t.Fatalf("expected OsakaBlock to remain nil, have %v", resolvedCfg.OsakaBlock) + } +} + +func TestSetupGenesisCustomChainProvidedGenesisThenRestartWithoutGenesis(t *testing.T) { + db := rawdb.NewMemoryDatabase() + cfg := params.XDCMainnetChainConfig.Clone() + cfg.ChainID = big.NewInt(8888) + cfg.XDPoS = nil + cfg.Ethash = new(params.EthashConfig) + cfg.OsakaBlock = nil + + genesis := &Genesis{ + Config: cfg, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + + initialCfg, hash, _, err := SetupGenesisBlock(db, genesis) + if err != nil { + t.Fatalf("initial SetupGenesisBlock failed: %v", err) + } + if initialCfg == nil { + t.Fatal("expected initial config") + } + if initialCfg.OsakaBlock != nil { + t.Fatalf("expected OsakaBlock to remain nil after initial setup, have %v", initialCfg.OsakaBlock) + } + + restartedCfg, restartedHash, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("restart SetupGenesisBlock failed: %v", err) + } + if restartedCfg == nil { + t.Fatal("expected restart config") + } + if restartedHash != hash { + t.Fatalf("unexpected restart genesis hash: have %s want %s", restartedHash.Hex(), hash.Hex()) + } + if restartedCfg.OsakaBlock != nil { + t.Fatalf("expected OsakaBlock to remain nil after restart, have %v", restartedCfg.OsakaBlock) + } +} + +func TestLoadChainConfigAllowsLegacyCustomChainWithCompleteMigratedForkFields(t *testing.T) { + db := rawdb.NewMemoryDatabase() + cfg := params.XDCMainnetChainConfig.Clone() + cfg.ChainID = big.NewInt(9898) + cfg.XDPoS = nil + cfg.Ethash = new(params.EthashConfig) + + genesis := &Genesis{ + Config: cfg, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + block := genesis.MustCommit(db) + + loadedCfg, loadedHash, err := LoadChainConfig(db, nil) + if err != nil { + t.Fatalf("LoadChainConfig failed: %v", err) + } + if loadedCfg == nil { + t.Fatal("expected loaded config") + } + if loadedHash != block.Hash() { + t.Fatalf("unexpected genesis hash: have %s want %s", loadedHash.Hex(), block.Hash().Hex()) + } +} + +func TestLoadChainConfigUsesStoredBuiltInHashWhenChainConfigMissing(t *testing.T) { + db := rawdb.NewMemoryDatabase() + block := DefaultTestnetGenesisBlock().ToBlock() + rawdb.WriteBlock(db, block) + rawdb.WriteHeadHeaderHash(db, block.Hash()) + rawdb.WriteCanonicalHash(db, block.Hash(), 0) + rawdb.WriteChainConfig(db, block.Hash(), params.TestnetChainConfig) + + cfg, hash, err := LoadChainConfig(db, nil) + if err != nil { + t.Fatalf("LoadChainConfig failed: %v", err) + } + if hash != params.TestnetGenesisHash { + t.Fatalf("unexpected hash: have %s want %s", hash.Hex(), params.TestnetGenesisHash.Hex()) + } + if !chainConfigSemanticallyEqual(cfg, params.TestnetChainConfig) { + t.Fatalf("unexpected config: have %v want %v", cfg, params.TestnetChainConfig) + } +} + +func TestLoadChainConfigReturnsBuiltInConfigInstanceWhenStoredBuiltInConfigMissingFields(t *testing.T) { + db := rawdb.NewMemoryDatabase() + DefaultTestnetGenesisBlock().MustCommit(db) + + stored := params.TestnetGenesisHash + rawCfg, err := rawdb.ReadChainConfigJSON(db, stored) + if err != nil { + t.Fatalf("failed to read raw chain config: %v", err) + } + updatedRawCfg, err := removeTopLevelFieldFromRawConfig(rawCfg, "eip1559Block") + if err != nil { + t.Fatalf("failed to remove eip1559Block from raw config: %v", err) + } + if err := db.Put(testConfigKey(stored), updatedRawCfg); err != nil { + t.Fatalf("failed to write modified raw chain config: %v", err) + } + + cfg, hash, err := LoadChainConfig(db, nil) + if err != nil { + t.Fatalf("LoadChainConfig failed: %v", err) + } + if hash != stored { + t.Fatalf("unexpected hash: have %s want %s", hash.Hex(), stored.Hex()) + } + if cfg != params.TestnetChainConfig { + t.Fatalf("expected in-memory built-in config instance, have %p want %p", cfg, params.TestnetChainConfig) + } + if cfg.Eip1559Block == nil { + t.Fatalf("expected eip1559Block from built-in config, got nil") + } +} + +func TestSetupGenesisBlockReturnsMarshalStoredConfigError(t *testing.T) { + db := rawdb.NewMemoryDatabase() + DefaultGenesisBlock().MustCommit(db) + + originalMarshal := jsonMarshal + defer func() { jsonMarshal = originalMarshal }() + + injectedErr := errors.New("injected marshal failure") + callCount := 0 + jsonMarshal = func(v any) ([]byte, error) { + callCount++ + if callCount == 1 { + return nil, injectedErr + } + return json.Marshal(v) + } + + _, _, _, err := SetupGenesisBlock(db, nil) + if err == nil { + t.Fatal("expected error, got nil") + } + if !strings.Contains(err.Error(), "failed to marshal stored chain config") { + t.Fatalf("unexpected error: %v", err) + } + if !errors.Is(err, injectedErr) { + t.Fatalf("expected injected error, got %v", err) + } +} + +func TestSetupGenesisBlockReturnsMarshalNewConfigError(t *testing.T) { + db := rawdb.NewMemoryDatabase() + DefaultGenesisBlock().MustCommit(db) + + originalMarshal := jsonMarshal + defer func() { jsonMarshal = originalMarshal }() + + injectedErr := errors.New("injected marshal failure") + callCount := 0 + jsonMarshal = func(v any) ([]byte, error) { + callCount++ + if callCount == 2 { + return nil, injectedErr + } + return json.Marshal(v) + } + + _, _, _, err := SetupGenesisBlock(db, nil) + if err == nil { + t.Fatal("expected error, got nil") + } + if !strings.Contains(err.Error(), "failed to marshal new chain config") { + t.Fatalf("unexpected error: %v", err) + } + if !errors.Is(err, injectedErr) { + t.Fatalf("expected injected error, got %v", err) + } +} + +func TestSetupGenesisTreatsCustomChainAsLocalnetWhenChainConfigMissing(t *testing.T) { + db := rawdb.NewMemoryDatabase() + cfg, hash, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if hash != params.MainnetGenesisHash { + t.Fatalf("unexpected hash: have %s want %s", hash.Hex(), params.MainnetGenesisHash.Hex()) + } + if cfg == nil { + t.Fatal("expected resolved config") + } + assertMigratedForkFieldsEqual(t, cfg, params.XDCMainnetChainConfig) +} + +func TestLoadChainConfigTreatsCustomChainAsLocalnetWhenChainConfigMissing(t *testing.T) { + db := rawdb.NewMemoryDatabase() + cfg, hash, err := LoadChainConfig(db, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if hash != params.MainnetGenesisHash { + t.Fatalf("unexpected hash: have %s want %s", hash.Hex(), params.MainnetGenesisHash.Hex()) + } + if cfg == nil { + t.Fatal("expected resolved config") + } + assertMigratedForkFieldsEqual(t, cfg, params.XDCMainnetChainConfig) +} + +func TestGenesisCommitRejectsMissingTIPTRC21FeeBlock(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(31337), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + + _, err := genesis.Commit(db) + if !errors.Is(err, params.ErrMissingForkSwitch) { + t.Fatalf("unexpected error: have %v want %v", err, params.ErrMissingForkSwitch) + } +} + +func TestSetupGenesisBackfillsMissingTIPTRC21FeeBlock(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(41414), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + + cfg, hash, _, err := SetupGenesisBlock(db, genesis) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if hash == (common.Hash{}) { + t.Fatalf("unexpected empty hash") + } + if cfg == nil || cfg.TIPTRC21FeeBlock == nil || cfg.TIPTRC21FeeBlock.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("expected TIPTRC21FeeBlock to be backfilled to 0, have %v", cfg) + } +} + +func TestLoadChainConfigBackfillsMissingTIPTRC21FeeBlock(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(51515), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + + cfg, hash, err := LoadChainConfig(db, genesis) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if cfg == nil { + t.Fatal("expected resolved config") + } + if hash == (common.Hash{}) { + t.Fatalf("unexpected empty hash") + } + if cfg.TIPTRC21FeeBlock == nil || cfg.TIPTRC21FeeBlock.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("expected TIPTRC21FeeBlock to be backfilled to 0, have %v", cfg.TIPTRC21FeeBlock) + } +} + +func TestLoadChainConfigBackfillsMissingStoredFieldForCustomNetworkReadPath(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(61616), + TIPTRC21FeeBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(12345), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + block := genesis.MustCommit(db) + + rawCfg, err := rawdb.ReadChainConfigJSON(db, block.Hash()) + if err != nil { + t.Fatalf("failed to read raw chain config: %v", err) + } + updatedRawCfg, err := removeTopLevelFieldFromRawConfig(rawCfg, "gas50xBlock") + if err != nil { + t.Fatalf("failed to remove gas50xBlock from raw config: %v", err) + } + if err := db.Put(testConfigKey(block.Hash()), updatedRawCfg); err != nil { + t.Fatalf("failed to write modified raw chain config: %v", err) + } + + cfg, hash, err := LoadChainConfig(db, nil) + if err != nil { + t.Fatalf("LoadChainConfig failed: %v", err) + } + if hash != block.Hash() { + t.Fatalf("unexpected hash: have %s want %s", hash.Hex(), block.Hash().Hex()) + } + if cfg == nil || cfg.Gas50xBlock == nil { + t.Fatalf("expected Gas50xBlock to be backfilled, have %v", cfg) + } + if cfg.Gas50xBlock.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("unexpected Gas50xBlock: have %v want 0 (Localnet default)", cfg.Gas50xBlock) + } +} + +func TestSetupGenesisBackfillsMissingStoredFieldForCustomNetworkReadPath(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(62626), + TIPTRC21FeeBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(12345), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + block := genesis.MustCommit(db) + + rawCfg, err := rawdb.ReadChainConfigJSON(db, block.Hash()) + if err != nil { + t.Fatalf("failed to read raw chain config: %v", err) + } + updatedRawCfg, err := removeTopLevelFieldFromRawConfig(rawCfg, "gas50xBlock") + if err != nil { + t.Fatalf("failed to remove gas50xBlock from raw config: %v", err) + } + if err := db.Put(testConfigKey(block.Hash()), updatedRawCfg); err != nil { + t.Fatalf("failed to write modified raw chain config: %v", err) + } + + cfg, hash, _, err := SetupGenesisBlock(db, nil) + if err != nil { + t.Fatalf("SetupGenesisBlock failed: %v", err) + } + if hash != block.Hash() { + t.Fatalf("unexpected hash: have %s want %s", hash.Hex(), block.Hash().Hex()) + } + if cfg == nil || cfg.Gas50xBlock == nil { + t.Fatalf("expected Gas50xBlock to be backfilled, have %v", cfg) + } + if cfg.Gas50xBlock.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("unexpected Gas50xBlock: have %v want 0 (Localnet default)", cfg.Gas50xBlock) + } +} + +func TestSetupGenesisBackfillsTIPTRC21FeeBlockForLocalnetChainID(t *testing.T) { + db := rawdb.NewMemoryDatabase() + genesis := &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(5151), + Ethash: new(params.EthashConfig), + }, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1)}, + }, + GasLimit: 4700000, + Difficulty: big.NewInt(1), + } + + cfg, _, _, err := SetupGenesisBlock(db, genesis) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if cfg == nil || cfg.TIPTRC21FeeBlock == nil || cfg.TIPTRC21FeeBlock.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("expected TIPTRC21FeeBlock to be backfilled to 0, have %v", cfg) + } +} + func TestSetupGenesis(t *testing.T) { var ( - customghash = common.HexToHash("0xfc8a143549950b0d3e3e7b70b0067b152e6b903ab5438f1ea87f0448ec93da48") - customg = Genesis{ - Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)}, + customg = Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(4444), + HomesteadBlock: big.NewInt(3), + TIPTRC21FeeBlock: big.NewInt(0), + Ethash: new(params.EthashConfig), + }, Alloc: types.GenesisAlloc{ {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, }, } - oldcustomg = customg + oldcustomg = customg + configReadErr = errors.New("chain config read failed") ) - oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)} + canonicalCustomCfg := canonicalizeChainConfig(common.Hash{}, customg.Config) + customg.Config = canonicalCustomCfg.Clone() + customghash := customg.ToBlock().Hash() + oldcustomg.Config = ¶ms.ChainConfig{ChainID: big.NewInt(4444), HomesteadBlock: big.NewInt(2), TIPTRC21FeeBlock: big.NewInt(0), Ethash: new(params.EthashConfig)} + oldcustomg.Config = canonicalizeChainConfig(common.Hash{}, oldcustomg.Config) tests := []struct { - name string - fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error) - wantConfig *params.ChainConfig - wantHash common.Hash - wantErr error + name string + fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error, error) + wantConfig *params.ChainConfig + wantHash common.Hash + wantErr error + wantCompactErr *params.ConfigCompatError }{ { name: "genesis without ChainConfig", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { return SetupGenesisBlock(db, new(Genesis)) }, wantErr: errGenesisNoConfig, - wantConfig: params.AllEthashProtocolChanges, + wantConfig: nil, }, { name: "no block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { return SetupGenesisBlock(db, nil) }, wantHash: params.MainnetGenesisHash, @@ -81,7 +1062,7 @@ func TestSetupGenesis(t *testing.T) { }, { name: "mainnet block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { DefaultGenesisBlock().MustCommit(db) return SetupGenesisBlock(db, nil) }, @@ -90,37 +1071,37 @@ func TestSetupGenesis(t *testing.T) { }, { name: "custom block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { customg.MustCommit(db) return SetupGenesisBlock(db, nil) }, wantHash: customghash, - wantConfig: customg.Config, + wantConfig: canonicalCustomCfg, }, { name: "custom block in DB, genesis == testnet", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { customg.MustCommit(db) return SetupGenesisBlock(db, DefaultTestnetGenesisBlock()) }, wantErr: &GenesisMismatchError{Stored: customghash, New: params.TestnetGenesisHash}, - wantHash: params.TestnetGenesisHash, - wantConfig: params.TestnetChainConfig, + wantHash: common.Hash{}, + wantConfig: nil, }, { name: "stored canonical hash without header", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { missingHash := common.HexToHash("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") rawdb.WriteCanonicalHash(db, missingHash, 0) return SetupGenesisBlock(db, nil) }, wantErr: fmt.Errorf("missing genesis header for hash: %s", common.HexToHash("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Hex()), wantHash: common.HexToHash("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), - wantConfig: params.AllEthashProtocolChanges, + wantConfig: nil, }, { name: "genesis header present but state missing", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { block := DefaultGenesisBlock().ToBlock() rawdb.WriteCanonicalHash(db, block.Hash(), 0) rawdb.WriteHeader(db, block.Header()) @@ -131,7 +1112,7 @@ func TestSetupGenesis(t *testing.T) { }, { name: "genesis block without chain config", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { block := DefaultGenesisBlock().ToBlock() rawdb.WriteBlock(db, block) rawdb.WriteCanonicalHash(db, block.Hash(), 0) @@ -140,9 +1121,25 @@ func TestSetupGenesis(t *testing.T) { wantHash: params.MainnetGenesisHash, wantConfig: params.XDCMainnetChainConfig, }, + { + name: "chain config read error does not trigger recovery", + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { + block := DefaultGenesisBlock().MustCommit(db) + brokenDB := &failingConfigReadDB{ + Database: db, + targetKey: testConfigKey(block.Hash()), + getErr: configReadErr, + hasResult: true, + } + return SetupGenesisBlock(brokenDB, nil) + }, + wantErr: fmt.Errorf("failed to read chain config for hash %s: %w", params.MainnetGenesisHash.Hex(), configReadErr), + wantHash: common.Hash{}, + wantConfig: nil, + }, { name: "missing block number for head header hash", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { DefaultGenesisBlock().MustCommit(db) rawdb.WriteHeadHeaderHash(db, common.HexToHash("0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")) return SetupGenesisBlock(db, nil) @@ -153,32 +1150,41 @@ func TestSetupGenesis(t *testing.T) { }, { name: "compatible config in DB", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { oldcustomg.MustCommit(db) - return SetupGenesisBlock(db, &customg) + genesis := customg + genesis.Config = customg.Config.Clone() + return SetupGenesisBlock(db, &genesis) }, wantHash: customghash, - wantConfig: customg.Config, + wantConfig: canonicalCustomCfg, }, { name: "incompatible config in DB", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error, error) { // Commit the 'old' genesis block with Homestead transition at #2. // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &oldcustomg, ethash.NewFullFaker(), vm.Config{}) + bc, err := NewBlockChain(db, nil, &oldcustomg, ethash.NewFullFaker(), vm.Config{}) + if err != nil { + return nil, common.Hash{}, err, nil + } defer bc.Stop() blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) - bc.InsertChain(blocks) + if _, err := bc.InsertChain(blocks); err != nil { + return nil, common.Hash{}, err, nil + } bc.CurrentBlock() // This should return a compatibility error. - return SetupGenesisBlock(db, &customg) + genesisCfg := customg + genesisCfg.Config = customg.Config.Clone() + return SetupGenesisBlock(db, &genesisCfg) }, wantHash: customghash, - wantConfig: customg.Config, - wantErr: ¶ms.ConfigCompatError{ + wantConfig: canonicalCustomCfg, + wantCompactErr: ¶ms.ConfigCompatError{ What: "Homestead fork block", StoredConfig: big.NewInt(2), NewConfig: big.NewInt(3), @@ -187,16 +1193,92 @@ func TestSetupGenesis(t *testing.T) { }, } + // Only compare fields explicitly set in the user's original config and required backfilled fields + chainConfigSemanticallyEqual := func(a, b *params.ChainConfig) bool { + if a == nil || b == nil { + return a == b + } + va := reflect.ValueOf(a).Elem() + vb := reflect.ValueOf(b).Elem() + fields := []string{"ChainID", "TIPTRC21FeeBlock", "XDPoS"} + // Add non-nil fields from b (only call IsNil on types that support it) + nilKinds := map[reflect.Kind]bool{ + reflect.Pointer: true, reflect.Slice: true, reflect.Map: true, reflect.Chan: true, reflect.Func: true, reflect.Interface: true, + } + typeOfCfg := va.Type() + for i := 0; i < vb.NumField(); i++ { + fname := typeOfCfg.Field(i).Name + if slices.Contains(fields, fname) { + continue + } + fieldVal := vb.Field(i) + if nilKinds[fieldVal.Kind()] && !fieldVal.IsNil() { + fields = append(fields, fname) + } + } + for _, fname := range fields { + fa := va.FieldByName(fname) + fb := vb.FieldByName(fname) + if !fa.IsValid() || !fb.IsValid() { + return false + } + // For *big.Int pointers + if fa.Type().String() == "*big.Int" { + if fa.Kind() == reflect.Ptr && fb.Kind() == reflect.Ptr { + if (fa.IsNil() && !fb.IsNil()) || (!fa.IsNil() && fb.IsNil()) { + return false + } + if !fa.IsNil() && fa.Interface().(*big.Int).Cmp(fb.Interface().(*big.Int)) != 0 { + return false + } + continue + } + } + // For XDPoS field + if fname == "XDPoS" { + if !params.XDPoSConfigEqual(fa.Interface().(*params.XDPoSConfig), fb.Interface().(*params.XDPoSConfig)) { + return false + } + continue + } + // Only call IsNil on types that support it + nilKinds := map[reflect.Kind]bool{ + reflect.Ptr: true, reflect.Slice: true, reflect.Map: true, reflect.Chan: true, reflect.Func: true, reflect.Interface: true, + } + if !nilKinds[fa.Kind()] { + if !reflect.DeepEqual(fa.Interface(), fb.Interface()) { + return false + } + continue + } + // Only proceed if both sides support IsNil + if fa.IsNil() != fb.IsNil() { + return false + } + if fa.IsNil() && fb.IsNil() { + continue + } + if !reflect.DeepEqual(fa.Interface(), fb.Interface()) { + return false + } + } + return true + } + for _, test := range tests { db := rawdb.NewMemoryDatabase() - config, hash, err := test.fn(db) + config, hash, compatErr, err := test.fn(db) // Check the return values. - if (err == nil) != (test.wantErr == nil) || (err != nil && test.wantErr != nil && !errors.Is(err, test.wantErr) && err.Error() != test.wantErr.Error()) { + if !chainConfigSemanticallyEqual(config, test.wantConfig) { + t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig) + } + if !reflect.DeepEqual(err, test.wantErr) { spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr)) } - if !reflect.DeepEqual(config, test.wantConfig) { - t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig) + if !reflect.DeepEqual(compatErr, test.wantCompactErr) { + spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} + t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(compatErr), spew.NewFormatter(test.wantCompactErr)) } if hash != test.wantHash { t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex()) @@ -209,3 +1291,48 @@ func TestSetupGenesis(t *testing.T) { } } } + +func TestSetupGenesisConfigCompatibilityPathReturnsConfig(t *testing.T) { + customg := Genesis{ + Config: ¶ms.ChainConfig{ChainID: big.NewInt(4444), HomesteadBlock: big.NewInt(3), TIPTRC21FeeBlock: big.NewInt(0), Ethash: new(params.EthashConfig)}, + Alloc: types.GenesisAlloc{ + {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, + }, + } + oldcustomg := customg + oldcustomg.Config = ¶ms.ChainConfig{ChainID: big.NewInt(4444), HomesteadBlock: big.NewInt(2), TIPTRC21FeeBlock: big.NewInt(0), Ethash: new(params.EthashConfig)} + customg.Config = canonicalizeChainConfig(common.Hash{}, customg.Config) + oldcustomg.Config = canonicalizeChainConfig(common.Hash{}, oldcustomg.Config) + + db := rawdb.NewMemoryDatabase() + genesis := oldcustomg.MustCommit(db) + + bc, err := NewBlockChain(db, nil, &oldcustomg, ethash.NewFullFaker(), vm.Config{}) + if err != nil { + t.Fatalf("failed to create blockchain: %v", err) + } + defer bc.Stop() + + blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) + if _, err := bc.InsertChain(blocks); err != nil { + t.Fatalf("failed to insert chain: %v", err) + } + + config, hash, compatErr, gotErr := SetupGenesisBlock(db, &customg) + if compatErr == nil { + t.Fatal("expected compatibility error") + } + if compatErr.What != "Homestead fork block" || compatErr.RewindTo != 1 { + t.Fatalf("unexpected compatibility error: %v", compatErr) + } + if gotErr != nil { + t.Fatalf("unexpected setup error: have %v want ConfigCompatError", gotErr) + } + if config == nil { + t.Fatal("unexpected nil config") + } + wantHash := genesis.Hash() + if hash != wantHash { + t.Fatalf("unexpected hash: have %s want %s", hash.Hex(), wantHash.Hex()) + } +} diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index c944e910abc0..0d1c0f274d21 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -19,6 +19,7 @@ package rawdb import ( "bytes" "encoding/hex" + "errors" "fmt" "math/big" "math/rand/v2" @@ -33,6 +34,50 @@ import ( "github.com/XinFinOrg/XDPoSChain/rlp" ) +type errorReader struct { + hasResult bool + hasErr error + getErr error + value []byte +} + +func (r *errorReader) Has(key []byte) (bool, error) { + return r.hasResult, r.hasErr +} + +func (r *errorReader) Get(key []byte) ([]byte, error) { + if r.getErr != nil { + return nil, r.getErr + } + return r.value, nil +} + +func TestReadChainConfigGetError(t *testing.T) { + hash := common.HexToHash("0x1") + wantErr := errors.New("boom") + _, err := ReadChainConfig(&errorReader{getErr: wantErr, hasResult: true}, hash) + if !errors.Is(err, wantErr) { + t.Fatalf("expected wrapped get error, got %v", err) + } +} + +func TestReadChainConfigNotFound(t *testing.T) { + hash := common.HexToHash("0x2") + _, err := ReadChainConfig(&errorReader{getErr: errors.New("missing"), hasResult: false}, hash) + if !errors.Is(err, ErrChainConfigNotFound) { + t.Fatalf("expected ErrChainConfigNotFound, got %v", err) + } +} + +func TestReadChainConfigJSONGetError(t *testing.T) { + hash := common.HexToHash("0x3") + wantErr := errors.New("boom") + _, err := ReadChainConfigJSON(&errorReader{getErr: wantErr, hasResult: true}, hash) + if !errors.Is(err, wantErr) { + t.Fatalf("expected wrapped get error, got %v", err) + } +} + type fullLogRLP struct { Address common.Address Topics []common.Hash diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go index efb6b0c68383..17ab94534a18 100644 --- a/core/rawdb/accessors_metadata.go +++ b/core/rawdb/accessors_metadata.go @@ -28,6 +28,23 @@ import ( "github.com/XinFinOrg/XDPoSChain/rlp" ) +var ErrChainConfigNotFound = errors.New("chain config not found") + +func readOptionalBlob(db ethdb.KeyValueReader, key []byte) ([]byte, error) { + blob, err := db.Get(key) + if err == nil { + return blob, nil + } + has, hasErr := db.Has(key) + if hasErr == nil && !has { + return nil, ErrChainConfigNotFound + } + if hasErr != nil { + return nil, fmt.Errorf("get failed: %w (has failed: %v)", err, hasErr) + } + return nil, err +} + // ReadDatabaseVersion retrieves the version number of the database. func ReadDatabaseVersion(db ethdb.KeyValueReader) *uint64 { var version uint64 @@ -56,9 +73,15 @@ func WriteDatabaseVersion(db ethdb.KeyValueWriter, version uint64) { // ReadChainConfig will fetch the network settings based on the given hash. func ReadChainConfig(db ethdb.KeyValueReader, hash common.Hash) (*params.ChainConfig, error) { - jsonChainConfig, _ := db.Get(configKey(hash)) + jsonChainConfig, err := readOptionalBlob(db, configKey(hash)) + if err != nil { + if errors.Is(err, ErrChainConfigNotFound) { + return nil, err + } + return nil, fmt.Errorf("failed to read chain config for hash %s: %w", hash.Hex(), err) + } if len(jsonChainConfig) == 0 { - return nil, errors.New("ChainConfig not found") // general config not found error + return nil, ErrChainConfigNotFound } var config params.ChainConfig @@ -70,6 +93,15 @@ func ReadChainConfig(db ethdb.KeyValueReader, hash common.Hash) (*params.ChainCo return &config, nil } +// ReadChainConfigJSON fetches the raw JSON chain config blob for the given hash. +func ReadChainConfigJSON(db ethdb.KeyValueReader, hash common.Hash) ([]byte, error) { + jsonChainConfig, err := readOptionalBlob(db, configKey(hash)) + if err != nil { + return nil, err + } + return jsonChainConfig, nil +} + // WriteChainConfig writes the chain config settings to the database. func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, cfg *params.ChainConfig) { if cfg == nil { diff --git a/core/state/statedb.go b/core/state/statedb.go index 922b663ec835..c6a82033f479 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -110,6 +110,8 @@ type StateDB struct { // when accessing state of accounts. dbErr error + chainConfig *params.ChainConfig + // The refund counter, also used by state transitioning. refund uint64 @@ -196,6 +198,42 @@ func (s *StateDB) Error() error { return s.dbErr } +func (s *StateDB) SetChainConfig(config *params.ChainConfig) { + s.chainConfig = config +} + +func (s *StateDB) ChainConfig() *params.ChainConfig { + return s.chainConfig +} + +func (s *StateDB) TRC21IssuerSMC() common.Address { + if s.chainConfig == nil { + return common.Address{} + } + return s.chainConfig.TRC21IssuerSMC +} + +func (s *StateDB) XDCXListingSMC() common.Address { + if s.chainConfig == nil { + return common.Address{} + } + return s.chainConfig.XDCXListingSMC +} + +func (s *StateDB) RelayerRegistrationSMC() common.Address { + if s.chainConfig == nil { + return common.Address{} + } + return s.chainConfig.RelayerRegistrationSMC +} + +func (s *StateDB) LendingRegistrationSMC() common.Address { + if s.chainConfig == nil { + return common.Address{} + } + return s.chainConfig.LendingRegistrationSMC +} + // Reset clears out all ephemeral state objects from the state db, but keeps // the underlying state trie to avoid reloading data for the next operations. func (s *StateDB) Reset(root common.Hash) error { @@ -747,6 +785,7 @@ func (s *StateDB) Copy() *StateDB { stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct), mutations: make(map[common.Address]*mutation, len(s.mutations)), dbErr: s.dbErr, + chainConfig: s.chainConfig, refund: s.refund, thash: s.thash, txIndex: s.txIndex, diff --git a/core/state/trc21_reader.go b/core/state/trc21_reader.go index 549655fbf8f9..8733d7deda90 100644 --- a/core/state/trc21_reader.go +++ b/core/state/trc21_reader.go @@ -49,17 +49,18 @@ func (s *StateDB) GetTRC21FeeCapacityFromState() map[common.Address]*big.Int { } tokensCapacity := map[common.Address]*big.Int{} + issuer := s.TRC21IssuerSMC() slotTokens := SlotTRC21Issuer["tokens"] slotTokensHash := common.BigToHash(new(big.Int).SetUint64(slotTokens)) slotTokensState := SlotTRC21Issuer["tokensState"] - tokenCount := s.GetState(common.TRC21IssuerSMC, slotTokensHash).Big().Uint64() + tokenCount := s.GetState(issuer, slotTokensHash).Big().Uint64() for i := range tokenCount { key := GetLocDynamicArrAtElement(slotTokensHash, i, 1) - value := s.GetState(common.TRC21IssuerSMC, key) + value := s.GetState(issuer, key) if !value.IsZero() { token := common.BytesToAddress(value.Bytes()) balanceKey := GetLocMappingAtKey(token.Hash(), slotTokensState) - balanceHash := s.GetState(common.TRC21IssuerSMC, common.BigToHash(balanceKey)) + balanceHash := s.GetState(issuer, common.BigToHash(balanceKey)) tokensCapacity[common.BytesToAddress(token.Bytes())] = balanceHash.Big() } } @@ -151,9 +152,10 @@ func (s *StateDB) UpdateTRC21Fee(newBalance map[common.Address]*big.Int, totalFe } slotTokensState := SlotTRC21Issuer["tokensState"] + issuer := s.TRC21IssuerSMC() for token, value := range newBalance { balanceKey := GetLocMappingAtKey(token.Hash(), slotTokensState) - s.SetState(common.TRC21IssuerSMC, common.BigToHash(balanceKey), common.BigToHash(value)) + s.SetState(issuer, common.BigToHash(balanceKey), common.BigToHash(value)) } - s.SubBalance(common.TRC21IssuerSMC, totalFeeUsed, tracing.BalanceChangeUnspecified) + s.SubBalance(issuer, totalFeeUsed, tracing.BalanceChangeUnspecified) } diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index eee1e5aba0aa..af4849158955 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -63,7 +63,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c return } // Convert the transaction into an executable message and pre-cache its sender - msg, err := TransactionToMessage(tx, signer, nil, nil, header.BaseFee) + msg, err := TransactionToMessage(tx, signer, nil, nil, header.BaseFee, p.config) if err != nil { return // Also invalid block, bail out } diff --git a/core/state_processor.go b/core/state_processor.go index 3ed93362d786..8c187fa62147 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -68,6 +68,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tradingState *tradingstate.TradingStateDB, cfg vm.Config, tokensFee map[common.Address]*big.Int) (types.Receipts, []*types.Log, uint64, error) { + statedb.SetChainConfig(p.config) var ( receipts = make([]*types.Receipt, 0, len(block.Transactions())) usedGas = new(uint64) @@ -87,7 +88,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(tracingStateDB) } - if common.TIPSigning.Cmp(blockNumber) == 0 { + if p.config.TIPSigningBlock != nil && p.config.TIPSigningBlock.Cmp(blockNumber) == 0 { statedb.DeleteAddress(common.BlockSignersBinary) } parentState := statedb.Copy() @@ -107,7 +108,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra // Iterate over and process the individual transactions for i, tx := range block.Transactions() { // check denylist txs after hf - if block.Number().Uint64() >= common.DenylistHFNumber { + if p.config.IsDenylist(block.Number()) { // check if sender is in denylist if common.IsInDenylist(tx.From()) { return nil, nil, 0, fmt.Errorf("block contains transaction with sender in denylist: %v", tx.From().Hex()) @@ -118,14 +119,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra } } // validate minFee slot for XDCZ - if tx.IsXDCZApplyTransaction() { + if tx.IsXDCZApplyTransaction(p.config) { copyState := statedb.Copy() if err := ValidateXDCZApplyTransaction(p.bc, block.Number(), copyState, common.BytesToAddress(tx.Data()[4:])); err != nil { return nil, nil, 0, err } } // validate balance slot, token decimal for XDCX - if tx.IsXDCXApplyTransaction() { + if tx.IsXDCXApplyTransaction(p.config) { copyState := statedb.Copy() if err := ValidateXDCXApplyTransaction(p.bc, block.Number(), copyState, common.BytesToAddress(tx.Data()[4:])); err != nil { return nil, nil, 0, err @@ -138,7 +139,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra balanceFee = value } } - msg, err := TransactionToMessage(tx, signer, balanceFee, blockNumber, header.BaseFee) + msg, err := TransactionToMessage(tx, signer, balanceFee, blockNumber, header.BaseFee, p.config) if err != nil { return nil, nil, 0, err } @@ -151,7 +152,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) if tokenFeeUsed { - fee := common.GetGasFee(block.Header().Number.Uint64(), gas) + fee := common.GetGasFee(block.Header().Number.Uint64(), gas, p.config.TIPTRC21FeeBlock, p.config.Gas50xBlock) tokensFee[*tx.To()] = new(big.Int).Sub(tokensFee[*tx.To()], fee) balanceUpdated[*tx.To()] = tokensFee[*tx.To()] totalFeeUsed = totalFeeUsed.Add(totalFeeUsed, fee) @@ -166,6 +167,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra } func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, statedb *state.StateDB, tradingState *tradingstate.TradingStateDB, cfg vm.Config, tokensFee map[common.Address]*big.Int) (types.Receipts, []*types.Log, uint64, error) { + statedb.SetChainConfig(p.config) block := cBlock.block var ( receipts types.Receipts @@ -186,7 +188,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(tracingStateDB) } - if common.TIPSigning.Cmp(blockNumber) == 0 { + if p.config.TIPSigningBlock != nil && p.config.TIPSigningBlock.Cmp(blockNumber) == 0 { statedb.DeleteAddress(common.BlockSignersBinary) } if cBlock.stop { @@ -214,7 +216,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated receipts = make([]*types.Receipt, block.Transactions().Len()) for i, tx := range block.Transactions() { // check denylist txs after hf - if block.Number().Uint64() >= common.DenylistHFNumber { + if p.config.IsDenylist(block.Number()) { // check if sender is in denylist if common.IsInDenylist(tx.From()) { return nil, nil, 0, fmt.Errorf("block contains transaction with sender in denylist: %v", tx.From().Hex()) @@ -225,14 +227,14 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated } } // validate minFee slot for XDCZ - if tx.IsXDCZApplyTransaction() { + if tx.IsXDCZApplyTransaction(p.config) { copyState := statedb.Copy() if err := ValidateXDCZApplyTransaction(p.bc, block.Number(), copyState, common.BytesToAddress(tx.Data()[4:])); err != nil { return nil, nil, 0, err } } // validate balance slot, token decimal for XDCX - if tx.IsXDCXApplyTransaction() { + if tx.IsXDCXApplyTransaction(p.config) { copyState := statedb.Copy() if err := ValidateXDCXApplyTransaction(p.bc, block.Number(), copyState, common.BytesToAddress(tx.Data()[4:])); err != nil { return nil, nil, 0, err @@ -244,7 +246,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated balanceFee = value } } - msg, err := TransactionToMessage(tx, signer, balanceFee, blockNumber, header.BaseFee) + msg, err := TransactionToMessage(tx, signer, balanceFee, blockNumber, header.BaseFee, p.config) if err != nil { return nil, nil, 0, err } @@ -260,7 +262,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated receipts[i] = receipt allLogs = append(allLogs, receipt.Logs...) if tokenFeeUsed { - fee := common.GetGasFee(block.Header().Number.Uint64(), gas) + fee := common.GetGasFee(block.Header().Number.Uint64(), gas, p.config.TIPTRC21FeeBlock, p.config.Gas50xBlock) tokensFee[*tx.To()] = new(big.Int).Sub(tokensFee[*tx.To()], fee) balanceUpdated[*tx.To()] = tokensFee[*tx.To()] totalFeeUsed = totalFeeUsed.Add(totalFeeUsed, fee) @@ -374,7 +376,7 @@ func ApplyTransaction(tokensFee map[common.Address]*big.Int, evm *vm.EVM, gp *Ga } signer := types.MakeSigner(evm.ChainConfig(), header.Number) - msg, err := TransactionToMessage(tx, signer, balanceFee, header.Number, header.BaseFee) + msg, err := TransactionToMessage(tx, signer, balanceFee, header.Number, header.BaseFee, evm.ChainConfig()) if err != nil { return nil, 0, false, err } @@ -505,9 +507,6 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { return } forkBlock := evm.ChainConfig().PragueBlock - if forkBlock == nil { - forkBlock = common.PragueBlock - } if forkBlock == nil || blockNumber.Cmp(forkBlock) < 0 { return } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 0af690f58170..9ab94738fde4 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -23,6 +23,7 @@ import ( "fmt" "math" "math/big" + "strings" "testing" "github.com/XinFinOrg/XDPoSChain/common" @@ -57,6 +58,7 @@ func TestStateProcessorErrors(t *testing.T) { ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), ShanghaiBlock: big.NewInt(0), @@ -295,8 +297,9 @@ func TestStateProcessorErrors(t *testing.T) { // ErrTxTypeNotSupported, For this, we need an older chain { var ( - db = rawdb.NewMemoryDatabase() - gspec = &Genesis{ + db = rawdb.NewMemoryDatabase() + futureFork = big.NewInt(1_000_000_000) + gspec = &Genesis{ Config: ¶ms.ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), @@ -307,6 +310,15 @@ func TestStateProcessorErrors(t *testing.T) { ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: new(big.Int).Set(futureFork), + LondonBlock: new(big.Int).Set(futureFork), + MergeBlock: new(big.Int).Set(futureFork), + ShanghaiBlock: new(big.Int).Set(futureFork), + Eip1559Block: new(big.Int).Set(futureFork), + CancunBlock: new(big.Int).Set(futureFork), + PragueBlock: new(big.Int).Set(futureFork), + OsakaBlock: new(big.Int).Set(futureFork), }, Alloc: types.GenesisAlloc{ common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): types.Account{ @@ -341,6 +353,86 @@ func TestStateProcessorErrors(t *testing.T) { } } +func TestStateProcessorDenylistHardForkBoundary(t *testing.T) { + testDenylistedReceiver := common.HexToAddress("0x5248bfb72fd4f234e062d3e9bb76f08643004fcd") + if !common.IsInDenylist(&testDenylistedReceiver) { + t.Fatalf("test receiver is not denylisted: %v", testDenylistedReceiver.Hex()) + } + + key, err := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + if err != nil { + t.Fatalf("failed to parse test key: %v", err) + } + from := crypto.PubkeyToAddress(key.PublicKey) + + newConfig := func(forkBlock uint64) *params.ChainConfig { + return ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DenylistBlock: new(big.Int).SetUint64(forkBlock), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Eip1559Block: big.NewInt(0), + CancunBlock: big.NewInt(0), + PragueBlock: big.NewInt(0), + OsakaBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: nil, + Ethash: new(params.EthashConfig), + } + } + + run := func(t *testing.T, forkBlock uint64, expectDenylistErr bool) { + t.Helper() + + cfg := newConfig(forkBlock) + signer := types.LatestSigner(cfg) + tx, err := types.SignTx(types.NewTransaction(0, testDenylistedReceiver, big.NewInt(1), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, key) + if err != nil { + t.Fatalf("failed to sign tx: %v", err) + } + + gspec := &Genesis{ + Config: cfg, + Alloc: types.GenesisAlloc{ + from: { + Balance: big.NewInt(1_000_000_000_000_000_000), + Nonce: 0, + }, + }, + } + db := rawdb.NewMemoryDatabase() + blockchain, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) + defer blockchain.Stop() + + block := GenerateBadBlock(t, gspec.ToBlock(), ethash.NewFaker(), []*types.Transaction{tx}, cfg) + _, err = blockchain.InsertChain(types.Blocks{block}) + if err == nil { + t.Fatal("expected block import error") + } + + hasDenylistErr := strings.Contains(err.Error(), "receiver in denylist") + if hasDenylistErr != expectDenylistErr { + t.Fatalf("unexpected denylist error presence (fork=%d): have=%v err=%v", forkBlock, hasDenylistErr, err) + } + } + + t.Run("below hardfork does not trigger denylist guard", func(t *testing.T) { + run(t, 2, false) + }) + t.Run("at hardfork triggers denylist guard", func(t *testing.T) { + run(t, 1, true) + }) +} + // GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be // valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently // valid to be considered for import: @@ -397,6 +489,7 @@ func TestApplyTransactionWithEVMTracer(t *testing.T) { ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), Eip1559Block: big.NewInt(0), @@ -485,7 +578,7 @@ func TestApplyTransactionWithEVMTracer(t *testing.T) { Tracer: mockTracer, } - msg, err := TransactionToMessage(signedTx, signer, nil, nil, nil) + msg, err := TransactionToMessage(signedTx, signer, nil, nil, nil, config) if err != nil { t.Fatalf("Failed to create message: %v", err) } @@ -533,6 +626,7 @@ func TestApplyTransactionWithEVMStateChangeHooks(t *testing.T) { ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), Eip1559Block: big.NewInt(0), @@ -580,7 +674,7 @@ func TestApplyTransactionWithEVMStateChangeHooks(t *testing.T) { vmContext := NewEVMBlockContext(blockchain.CurrentBlock(), blockchain, nil) evmenv := vm.NewEVM(vmContext, hookedState, nil, blockchain.Config(), vm.Config{Tracer: hooks}) - msg, err := TransactionToMessage(signedTx, signer, nil, big.NewInt(1), nil) + msg, err := TransactionToMessage(signedTx, signer, nil, big.NewInt(1), nil, config) if err != nil { t.Fatalf("Failed to build message: %v", err) } @@ -608,6 +702,7 @@ func TestApplyTransactionWithEVMOnTxStartUsesExecutionGasPrice(t *testing.T) { ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), Eip1559Block: big.NewInt(0), @@ -665,7 +760,7 @@ func TestApplyTransactionWithEVMOnTxStartUsesExecutionGasPrice(t *testing.T) { }, } - msg, err := TransactionToMessage(signedTx, signer, nil, big.NewInt(1), nil) + msg, err := TransactionToMessage(signedTx, signer, nil, big.NewInt(1), nil, config) if err != nil { t.Fatalf("Failed to build message: %v", err) } @@ -695,12 +790,21 @@ func TestApplyTransactionWithEVMRejectsValueOverflow(t *testing.T) { t.Parallel() config := ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - Ethash: new(params.EthashConfig), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(1_000_000_000), + LondonBlock: big.NewInt(1_000_000_000), + MergeBlock: big.NewInt(1_000_000_000), + ShanghaiBlock: big.NewInt(1_000_000_000), + Eip1559Block: big.NewInt(1_000_000_000), + CancunBlock: big.NewInt(1_000_000_000), + PragueBlock: big.NewInt(1_000_000_000), + OsakaBlock: big.NewInt(1_000_000_000), + Ethash: new(params.EthashConfig), } signer := types.LatestSigner(config) key, err := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -734,7 +838,7 @@ func TestApplyTransactionWithEVMRejectsValueOverflow(t *testing.T) { if err != nil { t.Fatalf("Failed to sign tx: %v", err) } - msg, err := TransactionToMessage(signedTx, signer, nil, big.NewInt(1), nil) + msg, err := TransactionToMessage(signedTx, signer, nil, big.NewInt(1), nil, config) if err != nil { t.Fatalf("Failed to build message: %v", err) } @@ -814,6 +918,63 @@ func TestProcessParentBlockHashPragueGuard(t *testing.T) { } } +func TestTransactionToMessageRejectsMissingTokenFeeConfig(t *testing.T) { + config := params.TestChainConfig.Clone() + signer := types.LatestSigner(config) + key, err := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + if err != nil { + t.Fatalf("failed to create key: %v", err) + } + recipient := common.HexToAddress("0x1234567890123456789012345678901234567890") + tx := types.NewTransaction(0, recipient, big.NewInt(1), 21000, big.NewInt(1), nil) + signedTx, err := types.SignTx(tx, signer, key) + if err != nil { + t.Fatalf("failed to sign tx: %v", err) + } + + tests := []struct { + name string + cfg *params.ChainConfig + errContains string + }{ + { + name: "nil chain config", + cfg: nil, + errContains: "missing chain config", + }, + { + name: "nil gas50x block", + cfg: func() *params.ChainConfig { + cfg := params.TestChainConfig.Clone() + cfg.Gas50xBlock = nil + return cfg + }(), + errContains: "missing Gas50xBlock", + }, + { + name: "nil trc21 fee block", + cfg: func() *params.ChainConfig { + cfg := params.TestChainConfig.Clone() + cfg.TIPTRC21FeeBlock = nil + return cfg + }(), + errContains: "missing TIPTRC21FeeBlock", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := TransactionToMessage(signedTx, signer, big.NewInt(1), big.NewInt(1), nil, tt.cfg) + if err == nil { + t.Fatal("expected error, got nil") + } + if !strings.Contains(err.Error(), tt.errContains) { + t.Fatalf("unexpected error: %v", err) + } + }) + } +} + func TestProcessParentBlockHashBackfillMissingHistory(t *testing.T) { config := *params.MergedTestChainConfig statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New()))) diff --git a/core/state_transition.go b/core/state_transition.go index 388a84185c8b..d1e861906cba 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -18,6 +18,7 @@ package core import ( "bytes" + "errors" "fmt" "math" "math/big" @@ -158,7 +159,7 @@ type Message struct { } // TransactionToMessage converts a transaction into a Message. -func TransactionToMessage(tx *types.Transaction, s types.Signer, balanceFee, blockNumber, baseFee *big.Int) (*Message, error) { +func TransactionToMessage(tx *types.Transaction, s types.Signer, balanceFee, blockNumber, baseFee *big.Int, chainConfig *params.ChainConfig) (*Message, error) { msg := &Message{ Nonce: tx.Nonce(), GasLimit: tx.Gas(), @@ -177,9 +178,18 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, balanceFee, blo if balanceFee != nil { if blockNumber != nil { - if blockNumber.Cmp(common.BlockNumberGas50x) >= 0 { + if chainConfig == nil { + return nil, errors.New("missing chain config for token fee pricing") + } + if chainConfig.Gas50xBlock == nil { + return nil, errors.New("missing Gas50xBlock in chain config for token fee pricing") + } + if chainConfig.TIPTRC21FeeBlock == nil { + return nil, errors.New("missing TIPTRC21FeeBlock in chain config for token fee pricing") + } + if blockNumber.Cmp(chainConfig.Gas50xBlock) >= 0 { msg.GasPrice = new(big.Int).Set(common.GasPrice50x) - } else if blockNumber.Cmp(common.TIPTRC21Fee) > 0 { + } else if blockNumber.Cmp(chainConfig.TIPTRC21FeeBlock) > 0 { msg.GasPrice = new(big.Int).Set(common.TRC21GasPrice) } else { msg.GasPrice = new(big.Int).Set(common.TRC21GasPriceBefore) @@ -497,7 +507,7 @@ func (st *stateTransition) execute(owner common.Address) (*ExecutionResult, erro // GasPrice of special tx is always 0, so we can skip AddBalance if !types.IsSpecialTx(msg.To) { - if st.evm.Context.BlockNumber.Cmp(common.TIPTRC21Fee) > 0 { + if st.evm.Context.BlockNumber.Cmp(st.evm.ChainConfig().TIPTRC21FeeBlock) > 0 { if (owner != common.Address{}) { st.state.AddBalance(owner, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), msg.GasPrice), tracing.BalanceIncreaseRewardTransactionFee) } diff --git a/core/token_validator.go b/core/token_validator.go index de6289e52f53..dccbc3e88890 100644 --- a/core/token_validator.go +++ b/core/token_validator.go @@ -77,7 +77,12 @@ func RunContract(chain consensus.ChainContext, statedb *state.StateDB, contractA func CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext, statedb *state.StateDB) ([]byte, error) { // Ensure message is initialized properly. call.GasPrice = big.NewInt(0) - + if call.GasFeeCap == nil { + call.GasFeeCap = new(big.Int) + } + if call.GasTipCap == nil { + call.GasTipCap = new(big.Int) + } if call.Gas == 0 { call.Gas = 1000000 } @@ -109,7 +114,7 @@ func CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext, // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. evmContext := NewEVMBlockContext(chain.CurrentHeader(), chain, nil) - evm := vm.NewEVM(evmContext, statedb, nil, chain.Config(), vm.Config{}) + evm := vm.NewEVM(evmContext, statedb, nil, chain.Config(), vm.Config{NoBaseFee: true}) gaspool := new(GasPool).AddGas(1000000) result, err := ApplyMessage(evm, msg, gaspool, common.Address{}) if err != nil { diff --git a/core/txpool/errors.go b/core/txpool/errors.go index 3f4c1161adc8..68d3aeebd8e6 100644 --- a/core/txpool/errors.go +++ b/core/txpool/errors.go @@ -84,5 +84,9 @@ var ( // by an account that is not an authorized signer. ErrSpecialTxNotFromSigner = errors.New("special transaction sender is not a signer") + // ErrMissingChainConfig is returned when txpool validation is invoked without + // a chain config. This prevents silently skipping fork-gated checks. + ErrMissingChainConfig = errors.New("missing chain config") + ErrMinDeploySMC = errors.New("smart contract creation cost is under allowance") ) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 3ac2ab2132dd..642cd21fb45f 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -585,6 +585,8 @@ func (pool *LegacyPool) ValidateTxBasics(tx *types.Transaction) error { // rules and adheres to some heuristic limits of the local node (price and size). func (pool *LegacyPool) validateTx(tx *types.Transaction) error { opts := &txpool.ValidationOptionsWithState{ + Config: pool.chainconfig, + State: pool.currentState, FirstNonceGap: nil, // Pool allows arbitrary arrival order, don't invalidate nonce gaps @@ -623,13 +625,13 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error { } // Validate minFee slot for XDCZ - if tx.IsXDCZApplyTransaction() { + if tx.IsXDCZApplyTransaction(pool.chain.Config()) { copyState := opts.State.Copy() return core.ValidateXDCZApplyTransaction(pool.chain, nil, copyState, common.BytesToAddress(tx.Data()[4:])) } // Validate balance slot, token decimal for XDCX - if tx.IsXDCXApplyTransaction() { + if tx.IsXDCXApplyTransaction(pool.chain.Config()) { copyState := opts.State.Copy() return core.ValidateXDCXApplyTransaction(pool.chain, nil, copyState, common.BytesToAddress(tx.Data()[4:])) } @@ -1498,7 +1500,7 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T if head := pool.chain.CurrentHeader(); head != nil { number = head.Number } - promotable, dropped, removedAddresses := pool.queue.promoteExecutables(accounts, gasLimit, pool.currentState, pool.pendingNonces, pool.trc21FeeCapacity, number) + promotable, dropped, removedAddresses := pool.queue.promoteExecutables(accounts, gasLimit, pool.currentState, pool.pendingNonces, pool.trc21FeeCapacity, number, pool.chainconfig.Gas50xBlock) // promote all promotable transactions promoted := make([]*types.Transaction, 0, len(promotable)) @@ -1650,7 +1652,7 @@ func (pool *LegacyPool) demoteUnexecutables() { if pool.chain.CurrentHeader() != nil { number = pool.chain.CurrentHeader().Number } - drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit, pool.trc21FeeCapacity, number) + drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit, pool.trc21FeeCapacity, number, pool.chainconfig.Gas50xBlock) for _, tx := range drops { hash := tx.Hash() pool.all.Remove(hash) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index f4afdb1bcdb0..5c68604fb546 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -1571,7 +1571,7 @@ func TestAllowedTxSize(t *testing.T) { account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000000000000000)) - minGasPrice := common.GetMinGasPrice(pool.currentHead.Load().Number) + minGasPrice := common.GetMinGasPrice(pool.currentHead.Load().Number, pool.chainconfig.Gas50xBlock) // Find the maximum data length for the kind of transaction which will // be generated in the pool.addRemoteSync calls below. @@ -1815,7 +1815,7 @@ func TestMinGasPriceEnforced(t *testing.T) { key, _ := crypto.GenerateKey() testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1_000_000_000_000_000_000)) - minGasPrice := common.GetMinGasPrice(blockchain.CurrentBlock().Number) + minGasPrice := common.GetMinGasPrice(blockchain.CurrentBlock().Number, blockchain.Config().Gas50xBlock) legacyPrice := new(big.Int).Add(minGasPrice, big.NewInt(1)) dynamicTip := new(big.Int).Add(minGasPrice, big.NewInt(1)) dynamicFeeCap := new(big.Int).Add(minGasPrice, big.NewInt(2)) diff --git a/core/txpool/legacypool/list.go b/core/txpool/legacypool/list.go index e806d9a6ff75..43d07413d68c 100644 --- a/core/txpool/legacypool/list.go +++ b/core/txpool/legacypool/list.go @@ -373,7 +373,7 @@ func (l *list) Forward(threshold uint64) types.Transactions { // a point in calculating all the costs or if the balance covers all. If the threshold // is lower than the costgas cap, the caps will be reset to a new high after removing // the newly invalidated transactions. -func (l *list) Filter(costLimit *big.Int, gasLimit uint64, trc21Issuers map[common.Address]*big.Int, number *big.Int) (types.Transactions, types.Transactions) { +func (l *list) Filter(costLimit *big.Int, gasLimit uint64, trc21Issuers map[common.Address]*big.Int, number, gas50xBlock *big.Int) (types.Transactions, types.Transactions) { // If all transactions are below the threshold, short circuit if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit { return nil, nil @@ -386,7 +386,7 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64, trc21Issuers map[comm maximum := costLimit if tx.To() != nil { if feeCapacity, ok := trc21Issuers[*tx.To()]; ok { - return tx.Gas() > gasLimit || new(big.Int).Add(costLimit, feeCapacity).Cmp(tx.TxCost(number)) < 0 + return tx.Gas() > gasLimit || new(big.Int).Add(costLimit, feeCapacity).Cmp(tx.TxCost(number, gas50xBlock)) < 0 } } return tx.Gas() > gasLimit || tx.Cost().Cmp(maximum) > 0 diff --git a/core/txpool/legacypool/list_test.go b/core/txpool/legacypool/list_test.go index 4aca0529c6d1..d9c733c12d9a 100644 --- a/core/txpool/legacypool/list_test.go +++ b/core/txpool/legacypool/list_test.go @@ -143,7 +143,7 @@ func BenchmarkListAdd(t *testing.B) { t.ResetTimer() for _, v := range rand.Perm(len(txs)) { list.Add(txs[v], DefaultConfig.PriceBump) - list.Filter(priceLimit, DefaultConfig.PriceBump, nil, nil) + list.Filter(priceLimit, DefaultConfig.PriceBump, nil, nil, nil) } } diff --git a/core/txpool/legacypool/queue.go b/core/txpool/legacypool/queue.go index a70c175438ce..03e1316e6b0a 100644 --- a/core/txpool/legacypool/queue.go +++ b/core/txpool/legacypool/queue.go @@ -160,7 +160,7 @@ func (q *queue) add(tx *types.Transaction) (*common.Hash, error) { // - all transactions that were removed from the queue and selected for promotion; // - all other transactions that were removed from the queue and dropped; // - the list of addresses removed. -func (q *queue) promoteExecutables(accounts []common.Address, gasLimit uint64, currentState *state.StateDB, nonces *noncer, trc21FeeCapacity map[common.Address]*big.Int, number *big.Int) ([]*types.Transaction, []common.Hash, []common.Address) { +func (q *queue) promoteExecutables(accounts []common.Address, gasLimit uint64, currentState *state.StateDB, nonces *noncer, trc21FeeCapacity map[common.Address]*big.Int, number, gas50xBlock *big.Int) ([]*types.Transaction, []common.Hash, []common.Address) { // Track the promotable transactions to broadcast them at once var ( promotable []*types.Transaction @@ -181,7 +181,7 @@ func (q *queue) promoteExecutables(accounts []common.Address, gasLimit uint64, c log.Trace("Removing old queued transactions", "count", len(forwards)) // Drop all transactions that are too costly (low balance or out of gas) - drops, _ := list.Filter(currentState.GetBalance(addr), gasLimit, trc21FeeCapacity, number) + drops, _ := list.Filter(currentState.GetBalance(addr), gasLimit, trc21FeeCapacity, number, gas50xBlock) for _, tx := range drops { dropped = append(dropped, tx.Hash()) } diff --git a/core/txpool/validation.go b/core/txpool/validation.go index cb214b70c676..9e70a3b5badc 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -153,6 +153,8 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types // ValidationOptionsWithState define certain differences between stateful transaction // validation across the different pools without having to duplicate those checks. type ValidationOptionsWithState struct { + Config *params.ChainConfig // Chain configuration to selectively validate based on current fork rules + State *state.StateDB // State database to check nonces and balances against // FirstNonceGap is an optional callback to retrieve the first nonce gap in @@ -187,6 +189,12 @@ type ValidationOptionsWithState struct { // This check is public to allow different transaction pools to check the stateful // rules without duplicating code and running the risk of missed updates. func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, opts *ValidationOptionsWithState) error { + if opts.Config == nil { + return ErrMissingChainConfig + } + if opts.State != nil { + opts.State.SetChainConfig(opts.Config) + } // Ensure the transaction adheres to nonce ordering from, err := types.Sender(signer, tx) // already validated (and cached), but cleaner to check if err != nil { @@ -222,7 +230,7 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op if !opts.State.ValidateTRC21Tx(from, *to, tx.Data()) { return core.ErrInsufficientFunds } - cost = tx.TxCost(number) + cost = tx.TxCost(number, opts.Config.Gas50xBlock) } } newBalance := new(big.Int).Add(balance, feeCapacity) @@ -255,7 +263,7 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op } // Ensure sender and receiver are not in denylist - if number == nil || number.Cmp(new(big.Int).SetUint64(common.DenylistHFNumber)) >= 0 { + if number == nil || opts.Config.IsDenylist(number) { // check if sender is in denylist if common.IsInDenylist(tx.From()) { return fmt.Errorf("reject transaction with sender in denylist: %v", tx.From().Hex()) @@ -268,7 +276,7 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op // Validate gas price if !tx.IsSpecialTransaction() { - minGasPrice := common.GetMinGasPrice(number) + minGasPrice := common.GetMinGasPrice(number, opts.Config.Gas50xBlock) if tx.GasPrice().Cmp(minGasPrice) < 0 { return ErrUnderMinGasPrice } diff --git a/core/txpool/validation_denylist_test.go b/core/txpool/validation_denylist_test.go new file mode 100644 index 000000000000..cc02d8abc349 --- /dev/null +++ b/core/txpool/validation_denylist_test.go @@ -0,0 +1,106 @@ +package txpool + +import ( + "math/big" + "strings" + "testing" + + "github.com/XinFinOrg/XDPoSChain/common" + "github.com/XinFinOrg/XDPoSChain/core/rawdb" + "github.com/XinFinOrg/XDPoSChain/core/state" + "github.com/XinFinOrg/XDPoSChain/core/tracing" + "github.com/XinFinOrg/XDPoSChain/core/types" + "github.com/XinFinOrg/XDPoSChain/crypto" + "github.com/XinFinOrg/XDPoSChain/params" +) + +func newValidationStateOpts(t *testing.T, cfg *params.ChainConfig, number *big.Int) (*types.Transaction, types.Signer, *ValidationOptionsWithState) { + t.Helper() + + statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase())) + if err != nil { + t.Fatalf("failed to create state: %v", err) + } + + key, err := crypto.GenerateKey() + if err != nil { + t.Fatalf("failed to generate key: %v", err) + } + from := crypto.PubkeyToAddress(key.PublicKey) + statedb.AddBalance(from, new(big.Int).Mul(big.NewInt(1_000_000), big.NewInt(params.Ether)), tracing.BalanceChangeUnspecified) + + denylistedReceiver := common.HexToAddress("0x5248bfb72fd4f234e062d3e9bb76f08643004fcd") + gasPrice := new(big.Int).Mul(new(big.Int).Set(common.MinGasPrice), big.NewInt(10)) + tx, err := types.SignTx( + types.NewTransaction(0, denylistedReceiver, big.NewInt(1), params.TxGas, gasPrice, nil), + types.HomesteadSigner{}, + key, + ) + if err != nil { + t.Fatalf("failed to sign tx: %v", err) + } + + opts := &ValidationOptionsWithState{ + Config: cfg, + State: statedb, + ExistingExpenditure: func(common.Address) *big.Int { + return new(big.Int) + }, + ExistingCost: func(common.Address, uint64) *big.Int { + return nil + }, + PendingNonce: func(common.Address) uint64 { + return 0 + }, + CurrentNumber: func() *big.Int { + return number + }, + } + + return tx, types.HomesteadSigner{}, opts +} + +func TestValidateTransactionWithStateDenylistHardForkBoundaries(t *testing.T) { + cfg := ¶ms.ChainConfig{DenylistBlock: big.NewInt(100), Gas50xBlock: big.NewInt(1000)} + + t.Run("missing chain config returns explicit error", func(t *testing.T) { + tx, signer, opts := newValidationStateOpts(t, nil, big.NewInt(100)) + opts.Config = nil + err := ValidateTransactionWithState(tx, signer, opts) + if err == nil { + t.Fatal("expected missing chain config error") + } + if err != ErrMissingChainConfig { + t.Fatalf("unexpected error: have %v want %v", err, ErrMissingChainConfig) + } + }) + + t.Run("below hard fork allows denylisted receiver", func(t *testing.T) { + tx, signer, opts := newValidationStateOpts(t, cfg, big.NewInt(99)) + if err := ValidateTransactionWithState(tx, signer, opts); err != nil { + t.Fatalf("unexpected error below hard fork: %v", err) + } + }) + + t.Run("at hard fork rejects denylisted receiver", func(t *testing.T) { + tx, signer, opts := newValidationStateOpts(t, cfg, big.NewInt(100)) + err := ValidateTransactionWithState(tx, signer, opts) + if err == nil { + t.Fatal("expected denylist error at hard fork") + } + if !strings.Contains(err.Error(), "receiver in denylist") { + t.Fatalf("unexpected error at hard fork: %v", err) + } + }) + + t.Run("above hard fork rejects denylisted receiver", func(t *testing.T) { + tx, signer, opts := newValidationStateOpts(t, cfg, big.NewInt(101)) + err := ValidateTransactionWithState(tx, signer, opts) + if err == nil { + t.Fatal("expected denylist error above hard fork") + } + if !strings.Contains(err.Error(), "receiver in denylist") { + t.Fatalf("unexpected error above hard fork: %v", err) + } + }) +} diff --git a/core/types/transaction.go b/core/types/transaction.go index 2112317aacb9..d417d3673225 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -28,6 +28,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common/hexutil" "github.com/XinFinOrg/XDPoSChain/crypto" + "github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/rlp" "github.com/holiman/uint256" ) @@ -538,8 +539,8 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e } // TxCost returns gas * gasPrice + value. -func (tx *Transaction) TxCost(number *big.Int) *big.Int { - total := new(big.Int).Mul(common.GetGasPrice(number), new(big.Int).SetUint64(tx.Gas())) +func (tx *Transaction) TxCost(number, gas50xBlock *big.Int) *big.Int { + total := new(big.Int).Mul(common.GetGasPrice(number, gas50xBlock), new(big.Int).SetUint64(tx.Gas())) total.Add(total, tx.Value()) return total } @@ -653,9 +654,9 @@ func (tx *Transaction) IsVotingTransaction() (bool, *common.Address) { return true, &m } -func (tx *Transaction) IsXDCXApplyTransaction() bool { +func (tx *Transaction) IsXDCXApplyTransaction(config *params.ChainConfig) bool { to := tx.To() - if to == nil || *to != common.XDCXListingSMC { + if config == nil || to == nil || *to != config.XDCXListingSMC { return false } data := tx.Data() @@ -668,9 +669,9 @@ func (tx *Transaction) IsXDCXApplyTransaction() bool { return method == common.XDCXApplyMethod } -func (tx *Transaction) IsXDCZApplyTransaction() bool { +func (tx *Transaction) IsXDCZApplyTransaction(config *params.ChainConfig) bool { to := tx.To() - if to == nil || *to != common.TRC21IssuerSMC { + if config == nil || to == nil || *to != config.TRC21IssuerSMC { return false } data := tx.Data() diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 1024e5cd5e8c..91d97a91da4a 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -20,7 +20,6 @@ import ( "crypto/ecdsa" "errors" "fmt" - "math" "math/big" "github.com/XinFinOrg/XDPoSChain/common" @@ -40,6 +39,9 @@ type sigCache struct { // MakeSigner returns a Signer based on the given chain config and block number. func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { + if config == nil { + return HomesteadSigner{} + } var signer Signer switch { case config.IsPrague(blockNumber): @@ -65,17 +67,19 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { // have the current block number available, use MakeSigner instead. func LatestSigner(config *params.ChainConfig) Signer { var signer Signer - if config.ChainID != nil { + if config != nil && config.ChainID != nil { switch { - case common.PragueBlock.Int64() != math.MaxInt64 || config.PragueBlock != nil: + case config.PragueBlock != nil: signer = NewPragueSigner(config.ChainID) - case common.Eip1559Block.Int64() != math.MaxInt64 || config.Eip1559Block != nil: + case config.Eip1559Block != nil: signer = NewLondonSigner(config.ChainID) case config.EIP155Block != nil: signer = NewEIP155Signer(config.ChainID) default: signer = HomesteadSigner{} } + } else { + signer = HomesteadSigner{} } return signer } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 6dffdb560537..2cbf81fc090f 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -519,6 +519,27 @@ func BenchmarkEffectiveGasTipCmp(b *testing.B) { }) } +func TestLatestSignerUsesModernSignerForXDPoSMockChainConfig(t *testing.T) { + signer := LatestSigner(params.TestXDPoSMockChainConfig) + if _, ok := signer.(pragueSigner); !ok { + t.Fatalf("unexpected signer type %T, want pragueSigner for TestXDPoSMockChainConfig", signer) + } +} + +func TestLatestSignerNilConfigReturnsHomesteadSigner(t *testing.T) { + signer := LatestSigner(nil) + if _, ok := signer.(HomesteadSigner); !ok { + t.Fatalf("unexpected signer type %T, want HomesteadSigner for nil config", signer) + } +} + +func TestMakeSignerNilConfigReturnsHomesteadSigner(t *testing.T) { + signer := MakeSigner(nil, big.NewInt(0)) + if _, ok := signer.(HomesteadSigner); !ok { + t.Fatalf("unexpected signer type %T, want HomesteadSigner for nil config", signer) + } +} + func TestEffectiveGasTipIntCmpMatchesBigIntSemantics(t *testing.T) { tests := []struct { name string diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 26092676a0d0..11107470313c 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -199,7 +199,12 @@ func TestCreateGas(t *testing.T) { BlockNumber: big.NewInt(0), } config := Config{} - chainConfig := params.AllEthashProtocolChanges + legacyConfig := *params.AllEthashProtocolChanges + legacyConfig.Eip1559Block = nil + legacyConfig.CancunBlock = nil + legacyConfig.PragueBlock = nil + legacyConfig.OsakaBlock = nil + chainConfig := &legacyConfig if tt.eip3860 { config.ExtraEips = []int{3860} chainConfig = params.MergedTestChainConfig diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 9105df844ab5..63ca9bb139d3 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -55,22 +55,23 @@ type Config struct { func setDefaults(cfg *Config) { if cfg.ChainConfig == nil { cfg.ChainConfig = ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: new(big.Int), - DAOForkBlock: new(big.Int), - DAOForkSupport: false, - EIP150Block: new(big.Int), - EIP155Block: new(big.Int), - EIP158Block: new(big.Int), - ByzantiumBlock: new(big.Int), - ConstantinopleBlock: new(big.Int), - PetersburgBlock: new(big.Int), - IstanbulBlock: new(big.Int), - BerlinBlock: new(big.Int), - LondonBlock: new(big.Int), - MergeBlock: new(big.Int), - ShanghaiBlock: new(big.Int), - Eip1559Block: new(big.Int), + ChainID: big.NewInt(1), + HomesteadBlock: new(big.Int), + DAOForkBlock: new(big.Int), + DAOForkSupport: false, + EIP150Block: new(big.Int), + EIP155Block: new(big.Int), + EIP158Block: new(big.Int), + ByzantiumBlock: new(big.Int), + ConstantinopleBlock: new(big.Int), + PetersburgBlock: new(big.Int), + IstanbulBlock: new(big.Int), + TIPXDCXCancellationFeeBlock: new(big.Int), + BerlinBlock: new(big.Int), + LondonBlock: new(big.Int), + MergeBlock: new(big.Int), + ShanghaiBlock: new(big.Int), + Eip1559Block: new(big.Int), } } diff --git a/eth/api_backend.go b/eth/api_backend.go index 3493dfc54812..98b288d90e73 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -557,7 +557,7 @@ func (b *EthAPIBackend) GetVotersRewards(masternodeAddr common.Address) map[comm var voterResults map[common.Address]*big.Int for signer, calcReward := range rewardSigners { if signer == masternodeAddr { - rewards, err := contracts.CalculateRewardForHolders(foundationWalletAddr, state, masternodeAddr, calcReward, number) + rewards, err := contracts.CalculateRewardForHolders(chain.Config(), foundationWalletAddr, state, masternodeAddr, calcReward, header.Number) if err != nil { log.Error("Fail to calculate reward for holders.", "error", err) return nil diff --git a/eth/backend.go b/eth/backend.go index acac40a8efc3..5446d2e26ef0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -131,9 +131,12 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin } // Resolve the effective chain config (and persist it when compatible) // before constructing the consensus engine so it initializes with final network settings. - chainConfig, _, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) - if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { - return nil, genesisErr + chainConfig, _, _, err := core.SetupGenesisBlock(chainDb, config.Genesis) + if chainConfig == nil { + return nil, fmt.Errorf("nil chain config returned from SetupGenesisBlock (err=%v)", err) + } + if err != nil { + return nil, err } // Set networkID to chainID by default. @@ -141,7 +144,7 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin if networkID == 0 { networkID = chainConfig.ChainID.Uint64() } - common.CopyConstants(networkID) + common.CopyConstants(chainConfig.ChainID.Uint64()) engine := CreateConsensusEngine(stack, chainConfig, chainDb) // Assemble the Ethereum object. diff --git a/eth/backend_test.go b/eth/backend_test.go index f30e23c09338..691c19ff2818 100644 --- a/eth/backend_test.go +++ b/eth/backend_test.go @@ -4,8 +4,10 @@ import ( "math/big" "testing" + "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core/rawdb" + "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/eth/util" "github.com/XinFinOrg/XDPoSChain/params" ) @@ -30,7 +32,32 @@ func TestRewardInflation(t *testing.T) { } } -func TestSetupGenesisBlockRepairsMissingV2Config(t *testing.T) { +func TestRewardInflationUsesChainConfigTIPNoHalvingMNReward(t *testing.T) { + chainReward := new(big.Int).Mul(new(big.Int).SetUint64(250), new(big.Int).SetUint64(params.Ether)) + config := ¶ms.ChainConfig{TIPNoHalvingMNRewardBlock: big.NewInt(20)} + reward := util.RewardInflation(testChainReader{cfg: config}, chainReward, 20, 10) + if reward.Cmp(new(big.Int).Mul(new(big.Int).SetUint64(250), new(big.Int).SetUint64(params.Ether))) != 0 { + t.Fatalf("unexpected reward with no-halving fork: have %v", reward) + } +} + +type testChainReader struct { + cfg *params.ChainConfig +} + +func (t testChainReader) Config() *params.ChainConfig { return t.cfg } + +func (testChainReader) CurrentHeader() *types.Header { return nil } + +func (testChainReader) GetHeader(common.Hash, uint64) *types.Header { return nil } + +func (testChainReader) GetHeaderByNumber(uint64) *types.Header { return nil } + +func (testChainReader) GetHeaderByHash(common.Hash) *types.Header { return nil } + +func (testChainReader) GetBlock(common.Hash, uint64) *types.Block { return nil } + +func TestSetupGenesisBlockResolvesMissingV2ConfigInMemory(t *testing.T) { db := rawdb.NewMemoryDatabase() legacyGenesis := legacyTestnetGenesisWithoutV2() @@ -43,11 +70,19 @@ func TestSetupGenesisBlockRepairsMissingV2Config(t *testing.T) { if loadedCfg.XDPoS == nil { t.Fatal("expected XDPoS config in loaded chain config") } - if loadedCfg.XDPoS.V2 != nil { - t.Fatal("expected stored legacy chain config to have nil XDPoS.V2 before setup") + + persistedBefore, err := rawdb.ReadChainConfig(db, params.TestnetGenesisHash) + if err != nil { + t.Fatalf("failed to read persisted chain config: %v", err) + } + if persistedBefore == nil || persistedBefore.XDPoS == nil { + t.Fatalf("expected persisted legacy chain config, have %v", persistedBefore) + } + if persistedBefore.XDPoS.V2 != nil { + t.Fatal("expected persisted legacy chain config to keep nil XDPoS.V2 before setup") } - finalCfg, _, err := core.SetupGenesisBlock(db, core.DefaultTestnetGenesisBlock()) + finalCfg, _, _, err := core.SetupGenesisBlock(db, core.DefaultTestnetGenesisBlock()) if err != nil { t.Fatalf("SetupGenesisBlock failed: %v", err) } @@ -57,17 +92,28 @@ func TestSetupGenesisBlockRepairsMissingV2Config(t *testing.T) { if finalCfg.XDPoS.V2.SwitchBlock.Cmp(params.TestnetChainConfig.XDPoS.V2.SwitchBlock) != 0 { t.Fatalf("unexpected switch block after setup: have %v want %v", finalCfg.XDPoS.V2.SwitchBlock, params.TestnetChainConfig.XDPoS.V2.SwitchBlock) } + + persistedAfter, err := rawdb.ReadChainConfig(db, params.TestnetGenesisHash) + if err != nil { + t.Fatalf("failed to read persisted chain config after setup: %v", err) + } + if persistedAfter == nil || persistedAfter.XDPoS == nil { + t.Fatalf("expected persisted chain config with XDPoS, have %v", persistedAfter) + } + if persistedAfter.XDPoS.V2 == nil { + t.Fatal("expected SetupGenesisBlock to persist in-memory V2 repair") + } } func TestSetupGenesisBlockIsIdempotentForTestnet(t *testing.T) { db := rawdb.NewMemoryDatabase() genesis := core.DefaultTestnetGenesisBlock() - cfg1, hash1, err := core.SetupGenesisBlock(db, genesis) + cfg1, hash1, _, err := core.SetupGenesisBlock(db, genesis) if err != nil { t.Fatalf("first SetupGenesisBlock failed: %v", err) } - cfg2, hash2, err := core.SetupGenesisBlock(db, genesis) + cfg2, hash2, _, err := core.SetupGenesisBlock(db, genesis) if err != nil { t.Fatalf("second SetupGenesisBlock failed: %v", err) } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index c2ca9171517b..409116464213 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -344,7 +344,7 @@ func (dl *downloadTester) handleProposedBlock(header *types.Header) error { // Config retrieves the blockchain's chain configuration. func (dl *downloadTester) Config() *params.ChainConfig { - config := *params.TestChainConfig + config := *testChainConfig return &config } diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 0125ef566cee..e3c3dee4fe88 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -33,14 +33,21 @@ import ( // Test chain parameters. var ( - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testAddress = crypto.PubkeyToAddress(testKey.PublicKey) - testDB = rawdb.NewMemoryDatabase() + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testAddress = crypto.PubkeyToAddress(testKey.PublicKey) + testDB = rawdb.NewMemoryDatabase() + testChainConfig = func() *params.ChainConfig { + cfg := *params.TestChainConfig + cfg.CancunBlock = nil + cfg.PragueBlock = nil + cfg.OsakaBlock = nil + return &cfg + }() testGspec = &core.Genesis{ Alloc: types.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), - Config: params.TestChainConfig, + Config: testChainConfig, } testGenesis = testGspec.MustCommit(testDB) ) @@ -138,7 +145,7 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool) } // Include transactions to the miner to make blocks more interesting. if parent == tc.genesis && i%22 == 0 { - signer := types.MakeSigner(params.TestChainConfig, block.Number()) + signer := types.MakeSigner(testChainConfig, block.Number()) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) if err != nil { panic(err) diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index e7ae052dc736..b6b1768daa21 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -99,7 +99,9 @@ func BenchmarkFilters(b *testing.B) { func TestFilters(t *testing.T) { config := *params.TestChainConfig - config.Eip1559Block = big.NewInt(0) + config.CancunBlock = nil + config.PragueBlock = nil + config.OsakaBlock = nil var ( db = rawdb.NewMemoryDatabase() diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 3ecca17dafe6..7b6140ed92cd 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -226,7 +226,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { // Check min gas price for non-eip1559 block if head.BaseFee == nil { - minGasPrice := common.GetMinGasPrice(head.Number) + minGasPrice := common.GetMinGasPrice(head.Number, oracle.backend.ChainConfig().Gas50xBlock) if price.Cmp(minGasPrice) < 0 { price = new(big.Int).Set(minGasPrice) } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 8942f473bf7d..bf0b5dba63f2 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -25,7 +25,6 @@ import ( "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/core" - "github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/crypto" @@ -109,6 +108,9 @@ func (b *testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) eve func newTestBackend(t *testing.T, eip1559Block *big.Int, pending bool) *testBackend { config := *params.TestChainConfig // needs copy because it is modified below + if eip1559Block == nil { + eip1559Block = big.NewInt(1_000_000_000) + } config.Eip1559Block = eip1559Block var ( @@ -123,11 +125,11 @@ func newTestBackend(t *testing.T, eip1559Block *big.Int, pending bool) *testBack engine := ethash.NewFaker() // Generate testing blocks - _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, testHead+1, func(i int, b *core.BlockGen) { + db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, testHead+1, func(i int, b *core.BlockGen) { b.SetCoinbase(common.Address{1}) var txdata types.TxData - if eip1559Block != nil && b.Number().Cmp(eip1559Block) >= 0 { + if b.Number().Cmp(config.Eip1559Block) >= 0 { txdata = &types.DynamicFeeTx{ ChainID: gspec.Config.ChainID, Nonce: b.TxNonce(addr), @@ -150,11 +152,13 @@ func newTestBackend(t *testing.T, eip1559Block *big.Int, pending bool) *testBack b.AddTx(types.MustSignNewTx(key, signer, txdata)) }) // Construct testing chain - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, engine, vm.Config{}) + chain, err := core.NewBlockChain(db, nil, gspec, engine, vm.Config{}) if err != nil { t.Fatalf("Failed to create local chain, %v", err) } - chain.InsertChain(blocks) + if _, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("Failed to insert generated chain, %v", err) + } return &testBackend{chain: chain, pending: pending} } diff --git a/eth/handler_test.go b/eth/handler_test.go index 07437a1cda87..8e5c58669dad 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -482,8 +482,10 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool db = rawdb.NewMemoryDatabase() gspec = &core.Genesis{ Config: ¶ms.ChainConfig{ - DAOForkBlock: big.NewInt(1), - DAOForkSupport: localForked, + ChainID: big.NewInt(1337), + TIPTRC21FeeBlock: big.NewInt(0), + DAOForkBlock: big.NewInt(1), + DAOForkSupport: localForked, }, } blockchain, _ = core.NewBlockChain(db, nil, gspec, pow, vm.Config{}) diff --git a/eth/hooks/engine_v1_hooks.go b/eth/hooks/engine_v1_hooks.go index d089b147dca3..7942518762f8 100644 --- a/eth/hooks/engine_v1_hooks.go +++ b/eth/hooks/engine_v1_hooks.go @@ -288,7 +288,7 @@ func AttachConsensusV1Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf voterResults := make(map[common.Address]interface{}) if len(signers) > 0 { for signer, calcReward := range rewardSigners { - rewards, err := contracts.CalculateRewardForHolders(foundationWalletAddr, parentState, signer, calcReward, number) + rewards, err := contracts.CalculateRewardForHolders(chain.Config(), foundationWalletAddr, parentState, signer, calcReward, header.Number) if err != nil { log.Crit("Fail to calculate reward for holders.", "error", err) } diff --git a/eth/hooks/engine_v2_hooks.go b/eth/hooks/engine_v2_hooks.go index 194ba818b2fa..2df6ecde32ec 100644 --- a/eth/hooks/engine_v2_hooks.go +++ b/eth/hooks/engine_v2_hooks.go @@ -312,7 +312,7 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf // Add reward for coin holders. rewardResults := make(map[common.Address]interface{}) for signer, calcReward := range rewardSigners { - rewards, err := contracts.CalculateRewardForHolders(foundationWalletAddr, parentState, signer, calcReward, number) + rewards, err := contracts.CalculateRewardForHolders(chain.Config(), foundationWalletAddr, parentState, signer, calcReward, header.Number) if err != nil { log.Error("[HookReward] Fail to calculate reward for holders.", "error", err) return nil, err @@ -350,7 +350,7 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf // Add reward for coin holders. rewardResults := make(map[common.Address]interface{}) for signer, calcReward := range rewardSigners { - rewards, err := contracts.CalculateRewardForHolders(foundationWalletAddr, parentState, signer, calcReward, number) + rewards, err := contracts.CalculateRewardForHolders(chain.Config(), foundationWalletAddr, parentState, signer, calcReward, header.Number) if err != nil { log.Error("[HookReward] Fail to calculate reward for holders.", "error", err) return nil, err diff --git a/eth/state_accessor.go b/eth/state_accessor.go index ecdf0d83e480..650df48a502f 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -229,7 +229,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, } } // Assemble the transaction call message and return if the requested offset - msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee(), eth.blockchain.Config()) // Not yet the searched for transaction, execute on top of the current state statedb.SetTxContext(tx.Hash(), idx) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 94cc8bfeba50..4eba59f8f9d1 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -275,7 +275,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed } } header := task.block.Header() - msg, _ := core.TransactionToMessage(tx, signer, balance, header.Number, header.BaseFee) + msg, _ := core.TransactionToMessage(tx, signer, balance, header.Number, header.BaseFee, api.backend.ChainConfig()) txctx := &Context{ BlockHash: task.block.Hash(), BlockNumber: task.block.Number(), @@ -539,7 +539,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config balance = value } } - msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee(), api.backend.ChainConfig()) statedb.SetTxContext(tx.Hash(), i) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) @@ -617,7 +617,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac } } // Generate the next state snapshot fast without tracing - msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee(), api.backend.ChainConfig()) txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), @@ -667,7 +667,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat } } header := block.Header() - msg, _ := core.TransactionToMessage(txs[task.index], signer, balance, header.Number, header.BaseFee) + msg, _ := core.TransactionToMessage(txs[task.index], signer, balance, header.Number, header.BaseFee, api.backend.ChainConfig()) txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), @@ -718,7 +718,7 @@ txloop: } // Generate the next state snapshot fast without tracing header := block.Header() - msg, _ := core.TransactionToMessage(tx, signer, balance, header.Number, header.BaseFee) + msg, _ := core.TransactionToMessage(tx, signer, balance, header.Number, header.BaseFee, api.backend.ChainConfig()) statedb.SetTxContext(tx.Hash(), i) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil { failed = err @@ -774,7 +774,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * balance = value } } - msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number()), balance, block.Number(), block.BaseFee()) + msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number()), balance, block.Number(), block.BaseFee(), api.backend.ChainConfig()) if err != nil { return nil, err } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index cb237b84dc01..ea675f882427 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -182,7 +182,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block if idx == txIndex { return tx, context, statedb, release, nil } - msg, _ := core.TransactionToMessage(tx, signer, nil, block.Number(), block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, nil, block.Number(), block.BaseFee(), b.chainConfig) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } @@ -251,7 +251,6 @@ func TestStateHooks(t *testing.T) { signer = types.HomesteadSigner{} nonce = uint64(0) ) - config.Eip1559Block = big.NewInt(0) backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] // value: 1000 wei @@ -302,7 +301,6 @@ func TestTraceCall(t *testing.T) { // Initialize test accounts config := *params.TestChainConfig - config.Eip1559Block = big.NewInt(0) accounts := newAccounts(3) genesis := &core.Genesis{ Config: &config, @@ -662,7 +660,6 @@ func TestTracingWithOverrides(t *testing.T) { // Initialize test accounts config := *params.TestChainConfig - config.Eip1559Block = big.NewInt(0) accounts := newAccounts(3) genesis := &core.Genesis{ Config: &config, diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index a68cf37198aa..6e8e17e032ec 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -112,6 +112,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } else if err := json.Unmarshal(blob, test); err != nil { t.Fatalf("failed to parse testcase: %v", err) } + test.Genesis.Config = ensureTracerChainConfig(test.Genesis.Config) if err := tx.UnmarshalBinary(common.FromHex(test.Input)); err != nil { t.Fatalf("failed to parse testcase input: %v", err) } @@ -139,7 +140,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if tracer.Hooks != nil { logState = state.NewHookedState(st, tracer.Hooks) } - msg, err := core.TransactionToMessage(tx, signer, nil, nil, context.BaseFee) + msg, err := core.TransactionToMessage(tx, signer, nil, nil, context.BaseFee, test.Genesis.Config) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } @@ -205,6 +206,7 @@ func BenchmarkTracers(b *testing.B) { if err := json.Unmarshal(blob, test); err != nil { b.Fatalf("failed to parse testcase: %v", err) } + test.Genesis.Config = ensureTracerChainConfig(test.Genesis.Config) benchTracer("callTracer", test, b) }) } @@ -218,7 +220,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { } signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) context := test.Context.toBlockContext(test.Genesis) - msg, err := core.TransactionToMessage(tx, signer, nil, nil, context.BaseFee) + msg, err := core.TransactionToMessage(tx, signer, nil, nil, context.BaseFee, test.Genesis.Config) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) } @@ -383,7 +385,7 @@ func TestInternals(t *testing.T) { t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err) } evm := vm.NewEVM(context, logState, nil, config, vm.Config{Tracer: tc.tracer.Hooks}) - msg, err := core.TransactionToMessage(tx, signer, nil, nil, big.NewInt(0)) + msg, err := core.TransactionToMessage(tx, signer, nil, nil, big.NewInt(0), config) if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) } @@ -436,6 +438,7 @@ func testContractTracer(tracerName string, dirPath string, t *testing.T) { } else if err := json.Unmarshal(blob, test); err != nil { t.Fatalf("failed to parse testcase: %v", err) } + test.Genesis.Config = ensureTracerChainConfig(test.Genesis.Config) if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { t.Fatalf("failed to parse testcase input: %v", err) } @@ -459,7 +462,7 @@ func testContractTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to create call tracer: %v", err) } evm := vm.NewEVM(context, state, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - msg, err := core.TransactionToMessage(tx, signer, nil, nil, nil) + msg, err := core.TransactionToMessage(tx, signer, nil, nil, nil, test.Genesis.Config) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index d65895befdf4..b2820cfc1480 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -78,6 +78,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err := json.Unmarshal(blob, test); err != nil { return fmt.Errorf("failed to parse testcase: %v", err) } + test.Genesis.Config = ensureTracerChainConfig(test.Genesis.Config) // Configure a blockchain with the given prestate tx := new(types.Transaction) if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { @@ -101,7 +102,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to create call tracer: %v", err) } - msg, err := core.TransactionToMessage(tx, signer, nil, context.BlockNumber, context.BaseFee) + msg, err := core.TransactionToMessage(tx, signer, nil, context.BlockNumber, context.BaseFee, test.Genesis.Config) if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index c418921d6b3f..d70eabcdb81a 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -86,6 +86,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { } else if err := json.Unmarshal(blob, test); err != nil { t.Fatalf("failed to parse testcase: %v", err) } + test.Genesis.Config = ensureTracerChainConfig(test.Genesis.Config) if err := tx.UnmarshalBinary(common.FromHex(test.Input)); err != nil { t.Fatalf("failed to parse testcase input: %v", err) } @@ -110,7 +111,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to create call tracer: %v", err) } - msg, err := core.TransactionToMessage(tx, signer, nil, context.BlockNumber, context.BaseFee) + msg, err := core.TransactionToMessage(tx, signer, nil, context.BlockNumber, context.BaseFee, test.Genesis.Config) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json index 877b9b035947..53a4f19b0a52 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json @@ -1,32 +1,30 @@ { - "genesis": { - "difficulty": "4671584", - "extraData": "0xd683010b05846765746886676f312e3133856c696e7578", - "gasLimit": "9435026", - "hash": "0x755bd54de4b2f5a7a589a10d69888b4ead48a6311d5d69f2f69ca85ec35fbe0b", + "context": { + "difficulty": "4669303", + "gasLimit": "9444238", "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "mixHash": "0x3a44525624571c31344ba57780f7664098fe7cbeafe532bcdee76a23fc474ba0", - "nonce": "0x6dca647c00c72bbf", - "number": "1555278", - "stateRoot": "0x5f56d8323ee384b0c8d1de49d63e150e17283eea813483698362bc0ec9e0242a", - "timestamp": "1590795319", - "totalDifficulty": "2242614315030", + "number": "1555279", + "timestamp": "1590795340" + }, + "genesis": { "alloc": { "0x0000000000000000000000000000000000000004": { "balance": "0x0", - "nonce": "0", "code": "0x", + "nonce": "0", "storage": {} }, "0x877bd459c9b7d8576b44e59e09d076c25946f443": { "balance": "0x62436e941792f02a5fb1", - "nonce": "265356", "code": "0x", + "nonce": "265356", "storage": {} } }, "config": { + "byzantiumBlock": 0, "chainId": 63, + "constantinopleBlock": 301243, "daoForkSupport": true, "eip150Block": 0, "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", @@ -34,57 +32,62 @@ "eip158Block": 0, "ethash": {}, "homesteadBlock": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 301243, - "petersburgBlock": 999983, - "istanbulBlock": 999983 - } - }, - "context": { - "number": "1555279", - "difficulty": "4669303", - "timestamp": "1590795340", - "gasLimit": "9444238", - "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + "istanbulBlock": 999983, + "petersburgBlock": 999983 + }, + "difficulty": "4671584", + "extraData": "0xd683010b05846765746886676f312e3133856c696e7578", + "gasLimit": "9435026", + "hash": "0x755bd54de4b2f5a7a589a10d69888b4ead48a6311d5d69f2f69ca85ec35fbe0b", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "mixHash": "0x3a44525624571c31344ba57780f7664098fe7cbeafe532bcdee76a23fc474ba0", + "nonce": "0x6dca647c00c72bbf", + "number": "1555278", + "stateRoot": "0x5f56d8323ee384b0c8d1de49d63e150e17283eea813483698362bc0ec9e0242a", + "timestamp": "1590795319", + "totalDifficulty": "2242614315030" }, "input": "0xf86f83040c8c843b9aca0083019f7880809b60206000600060006013600462030d40f26002556000516000550081a2a086ad228c89ad9664287b12a5602a635a803506904f4ce39795990ac4f945cd57a025b30ea8042d773f6c5b13d7cc1b3979f9f10ee674410b6a2112ce840d0302dc", "result": [ { - "type": "create", "action": { "creationMethod": "create", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "value": "0x0", "gas": "0x19f78", - "init": "0x60206000600060006013600462030d40f260025560005160005500" + "init": "0x60206000600060006013600462030d40f260025560005160005500", + "value": "0x0" }, + "blockHash": null, + "blockNumber": 0, "result": { - "gasUsed": "0xf800", + "address": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224", "code": "0x", - "address": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224" + "gasUsed": "0xf800" }, - "traceAddress": [], "subtraces": 1, - "transactionPosition": 74, - "transactionHash": "0x5ef60b27ac971c22a7d484e546e50093ca62300c8986d165154e47773764b6a4", - "blockNumber": 1555279, - "blockHash": "0xd6c98d1b87dfa92a210d99bad2873adaf0c9e51fe43addc63fd9cca03a5c6f46" + "traceAddress": [], + "transactionHash": null, + "transactionPosition": 0, + "type": "create" }, { "action": { - "balance": "0x0", "callType": "callcode", "from": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224", "gas": "0xab31", + "input": "0x", "to": "0x0000000000000000000000000000000000000004", "value": "0x13" }, + "blockHash": null, + "blockNumber": 0, "error": "insufficient balance for transfer", - "result": {}, "subtraces": 0, "traceAddress": [ 0 ], + "transactionHash": null, + "transactionPosition": 0, "type": "call" } ] diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json index 1136bcd8e319..d2ffd0861ceb 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json @@ -1,32 +1,30 @@ { - "genesis": { + "context": { "difficulty": "4671584", - "extraData": "0xd883010b05846765746888676f312e31342e33856c696e7578", - "gasLimit": "9425823", - "hash": "0x27dd7d052dbc8a29cc5b9487e1e41d842e7a643fcaea4964caa22b834964acaf", - "miner": "0x73f26d124436b0791169d63a3af29c2ae47765a3", - "mixHash": "0xb4a050624f5d147fdf02857cbfd55da3ddc1451743acc5c163861584589c3034", - "nonce": "0x3c255875b17e0573", - "number": "1555277", - "stateRoot": "0x6290d79215a2eebc25d5e456b35876c6d78ffc1ea47bdd70e375ebb3cf325620", - "timestamp": "1590795308", - "totalDifficulty": "2242609643446", + "gasLimit": "9435026", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "number": "1555278", + "timestamp": "1590795319" + }, + "genesis": { "alloc": { "0x0000000000000000000000000000000000000001": { "balance": "0x0", - "nonce": "0", "code": "0x", + "nonce": "0", "storage": {} }, "0x877bd459c9b7d8576b44e59e09d076c25946f443": { "balance": "0x624329308610ab365fb1", - "nonce": "265194", "code": "0x", + "nonce": "265194", "storage": {} } }, "config": { + "byzantiumBlock": 0, "chainId": 63, + "constantinopleBlock": 301243, "daoForkSupport": true, "eip150Block": 0, "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", @@ -34,59 +32,63 @@ "eip158Block": 0, "ethash": {}, "homesteadBlock": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 301243, - "petersburgBlock": 999983, - "istanbulBlock": 999983 - } - }, - "context": { - "number": "1555278", + "istanbulBlock": 999983, + "petersburgBlock": 999983 + }, "difficulty": "4671584", - "timestamp": "1590795319", - "gasLimit": "9435026", - "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + "extraData": "0xd883010b05846765746888676f312e31342e33856c696e7578", + "gasLimit": "9425823", + "hash": "0x27dd7d052dbc8a29cc5b9487e1e41d842e7a643fcaea4964caa22b834964acaf", + "miner": "0x73f26d124436b0791169d63a3af29c2ae47765a3", + "mixHash": "0xb4a050624f5d147fdf02857cbfd55da3ddc1451743acc5c163861584589c3034", + "nonce": "0x3c255875b17e0573", + "number": "1555277", + "stateRoot": "0x6290d79215a2eebc25d5e456b35876c6d78ffc1ea47bdd70e375ebb3cf325620", + "timestamp": "1590795308", + "totalDifficulty": "2242609643446" }, "input": "0xf8ee83040bea843b9aca008301a7588080b8997f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f260025560a060020a6080510660005560005432146001550081a1a05b9a162d84bfe84faa7c176e21c26c0083645d4dd0d566547b7be2c2da0b4259a05b37ff12a4c27634cb0da6008d9b69726d415ff4694f9bc38c7806eb1fb60ae9", "result": [ { - "type": "create", "action": { "creationMethod": "create", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "value": "0x0", "gas": "0x1a758", - "init": "0x7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f260025560a060020a60805106600055600054321460015500" + "init": "0x7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f260025560a060020a60805106600055600054321460015500", + "value": "0x0" }, + "blockHash": null, + "blockNumber": 0, "result": { - "gasUsed": "0x111c5", + "address": "0x568c19ecb14b87e4aec29b4d2d700a3ad3fd0613", "code": "0x", - "address": "0x568c19ecb14b87e4aec29b4d2d700a3ad3fd0613" + "gasUsed": "0x111c5" }, - "traceAddress": [], "subtraces": 1, - "transactionPosition": 141, - "transactionHash": "0x1592cbda0d928b8d18eed98857942b91ade32d088e55b8bf63418917cb0231f1", - "blockNumber": 1555278, - "blockHash": "0x755bd54de4b2f5a7a589a10d69888b4ead48a6311d5d69f2f69ca85ec35fbe0b" + "traceAddress": [], + "transactionHash": null, + "transactionPosition": 0, + "type": "create" }, { - "type": "call", "action": { + "callType": "callcode", "from": "0x568c19ecb14b87e4aec29b4d2d700a3ad3fd0613", - "to": "0x0000000000000000000000000000000000000001", - "value": "0x0", "gas": "0xbb7", "input": "0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", - "callType": "callcode" + "to": "0x0000000000000000000000000000000000000001", + "value": "0x0" }, + "blockHash": null, + "blockNumber": 0, "error": "out of gas", - "traceAddress": [0], "subtraces": 0, - "transactionPosition": 141, - "transactionHash": "0x1592cbda0d928b8d18eed98857942b91ade32d088e55b8bf63418917cb0231f1", - "blockNumber": 1555278, - "blockHash": "0x755bd54de4b2f5a7a589a10d69888b4ead48a6311d5d69f2f69ca85ec35fbe0b" + "traceAddress": [ + 0 + ], + "transactionHash": null, + "transactionPosition": 0, + "type": "call" } ] } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json index 87e002b4edb6..7468a4b1f496 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json @@ -1,32 +1,30 @@ { - "genesis": { + "context": { "difficulty": "4683014", - "extraData": "0x537465762d63676574682d76312e31312e34", - "gasLimit": "9435044", - "hash": "0x3452ca5005cb73cd60dfa488a7b124251168e564491f80eb66765e79d78cfd95", - "miner": "0x415aa6292d1db797a467b22139704956c030e62f", - "mixHash": "0x6037612618507ae70c74a72bc2580253662971db959cfbc06d3f8527d4d01575", - "nonce": "0x314fc90dee5e39a2", - "number": "1555274", - "stateRoot": "0x795751f3f96a5de1fd3944ddd78cbfe4ef10491e1086be47609869a30929d0e5", - "timestamp": "1590795228", - "totalDifficulty": "2242595605834", + "gasLimit": "9444256", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "number": "1555275", + "timestamp": "1590795244" + }, + "genesis": { "alloc": { "0x0000000000000000000000000000000000000009": { "balance": "0x0", - "nonce": "0", "code": "0x", + "nonce": "0", "storage": {} }, "0x877bd459c9b7d8576b44e59e09d076c25946f443": { "balance": "0x6242e3ccf48e66425fb1", - "nonce": "264981", "code": "0x", + "nonce": "264981", "storage": {} } }, "config": { + "byzantiumBlock": 0, "chainId": 63, + "constantinopleBlock": 301243, "daoForkSupport": true, "eip150Block": 0, "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", @@ -34,55 +32,59 @@ "eip158Block": 0, "ethash": {}, "homesteadBlock": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 301243, - "petersburgBlock": 999983, - "istanbulBlock": 999983 - } - }, - "context": { - "number": "1555275", + "istanbulBlock": 999983, + "petersburgBlock": 999983 + }, "difficulty": "4683014", - "timestamp": "1590795244", - "gasLimit": "9444256", - "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + "extraData": "0x537465762d63676574682d76312e31312e34", + "gasLimit": "9435044", + "hash": "0x3452ca5005cb73cd60dfa488a7b124251168e564491f80eb66765e79d78cfd95", + "miner": "0x415aa6292d1db797a467b22139704956c030e62f", + "mixHash": "0x6037612618507ae70c74a72bc2580253662971db959cfbc06d3f8527d4d01575", + "nonce": "0x314fc90dee5e39a2", + "number": "1555274", + "stateRoot": "0x795751f3f96a5de1fd3944ddd78cbfe4ef10491e1086be47609869a30929d0e5", + "timestamp": "1590795228", + "totalDifficulty": "2242595605834" }, "input": "0xf87a83040b15843b9aca008301a0348080a636600060003760406103e8366000600060095af26001556103e851600255610408516003550081a1a0dd883fbbb489b640dadc8c1bf151767155228d0a1321f687f070f35f14374b05a02dd0ccb16a8de39bc8ee61381bbbbb54f0ab18422afd7b03c6163da1f5023934", "result": [ { - "type": "create", "action": { "creationMethod": "create", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "value": "0x0", "gas": "0x1a034", - "init": "0x36600060003760406103e8366000600060095af26001556103e8516002556104085160035500" + "init": "0x36600060003760406103e8366000600060095af26001556103e8516002556104085160035500", + "value": "0x0" }, + "blockHash": null, + "blockNumber": 0, "error": "out of gas: not enough gas for reentrancy sentry", - "traceAddress": [], "subtraces": 1, - "transactionPosition": 117, - "transactionHash": "0x7fe4dec901e1a62c1a1d96b8267bb9ff9dc1f75def43aa45b998743455eff8f9", - "blockNumber": 1555275, - "blockHash": "0x80945caaff2fc67253cbb0217d2e5a307afde943929e97d8b36e58b88cbb02fd" + "traceAddress": [], + "transactionHash": null, + "transactionPosition": 0, + "type": "create" }, { - "type": "call", "action": { + "callType": "callcode", "from": "0x8832ef498070145c3a5b30f47fbca71fd7b1de9f", - "to": "0x0000000000000000000000000000000000000009", - "value": "0x0", "gas": "0xc1fe", "input": "0x", - "callType": "callcode" + "to": "0x0000000000000000000000000000000000000009", + "value": "0x0" }, + "blockHash": null, + "blockNumber": 0, "error": "invalid input length", - "traceAddress": [0], "subtraces": 0, - "transactionPosition": 117, - "transactionHash": "0x7fe4dec901e1a62c1a1d96b8267bb9ff9dc1f75def43aa45b998743455eff8f9", - "blockNumber": 1555275, - "blockHash": "0x80945caaff2fc67253cbb0217d2e5a307afde943929e97d8b36e58b88cbb02fd" + "traceAddress": [ + 0 + ], + "transactionHash": null, + "transactionPosition": 0, + "type": "call" } ] } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json index 1e421abc76b1..9396ec99e075 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json @@ -1,32 +1,30 @@ { + "context": { + "difficulty": "4642198", + "gasLimit": "9289249", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "number": "1555170", + "timestamp": "1590794112" + }, "genesis": { - "difficulty": "4639933", - "extraData": "0xd883010b05846765746888676f312e31342e33856c696e7578", - "gasLimit": "9280188", - "hash": "0x9a5f3a98eb1c60f6e3f450658a9cea190157e7021d04f927b752ad6482cf9194", - "miner": "0x73f26d124436b0791169d63a3af29c2ae47765a3", - "mixHash": "0x6b6f8fcaa54b8565c4c1ae7cf0a020e938a53007f4561e758b17bc05c9044d78", - "nonce": "0x773aba50dc51b462", - "number": "1555169", - "stateRoot": "0xc4b9703de3e59ff795baae2c3afa010cf039c37244a7a6af7f3f491a10601348", - "timestamp": "1590794111", - "totalDifficulty": "2242105342155", "alloc": { "0x5ac5599fc9df172c89ee7ec55ad9104ccbfed40d": { "balance": "0x0", - "nonce": "0", "code": "0x", + "nonce": "0", "storage": {} }, "0x877bd459c9b7d8576b44e59e09d076c25946f443": { "balance": "0x62325b40cbbd0915c4b9", - "nonce": "260875", "code": "0x", + "nonce": "260875", "storage": {} } }, "config": { + "byzantiumBlock": 0, "chainId": 63, + "constantinopleBlock": 301243, "daoForkSupport": true, "eip150Block": 0, "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", @@ -34,60 +32,62 @@ "eip158Block": 0, "ethash": {}, "homesteadBlock": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 301243, - "petersburgBlock": 999983, - "istanbulBlock": 999983 - } - }, - "context": { - "number": "1555170", - "difficulty": "4642198", - "timestamp": "1590794112", - "gasLimit": "9289249", - "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + "istanbulBlock": 999983, + "petersburgBlock": 999983 + }, + "difficulty": "4639933", + "extraData": "0xd883010b05846765746888676f312e31342e33856c696e7578", + "gasLimit": "9280188", + "hash": "0x9a5f3a98eb1c60f6e3f450658a9cea190157e7021d04f927b752ad6482cf9194", + "miner": "0x73f26d124436b0791169d63a3af29c2ae47765a3", + "mixHash": "0x6b6f8fcaa54b8565c4c1ae7cf0a020e938a53007f4561e758b17bc05c9044d78", + "nonce": "0x773aba50dc51b462", + "number": "1555169", + "stateRoot": "0xc4b9703de3e59ff795baae2c3afa010cf039c37244a7a6af7f3f491a10601348", + "timestamp": "1590794111", + "totalDifficulty": "2242105342155" }, "input": "0xf8658303fb0b843b9aca0083019ee48080915a600055600060006000f0505a6001550081a2a01a7deb3a16d967b766459ef486b00656c6581e5ad58968184a33701e27e0eb8aa07162ccdfe2018d64360a605310a62c399dd586c7282dd42a88c54f02f51d451f", "result": [ { - "type": "create", "action": { "creationMethod": "create", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "value": "0x0", "gas": "0x19ee4", - "init": "0x5a600055600060006000f0505a60015500" + "init": "0x5a600055600060006000f0505a60015500", + "value": "0x0" }, + "blockHash": null, + "blockNumber": 0, "error": "out of gas: not enough gas for reentrancy sentry", - "traceAddress": [], "subtraces": 1, - "transactionPosition": 63, - "transactionHash": "0x60e881fae3884657b5430925c5d0053535b45cce0b8188f2a6be1feee8bcc650", - "blockNumber": 1555170, - "blockHash": "0xea46fbf941d51bf1e4180fbf26d22fda3896f49c7f371d109c226de95dd7b02e" + "traceAddress": [], + "transactionHash": null, + "transactionPosition": 0, + "type": "create" }, { - "type": "create", "action": { "creationMethod": "create", "from": "0x9c5cfe45b15eaff4ad617af4250189e26024a4f8", - "value": "0x0", "gas": "0x165", - "init": "0x" + "init": "0x", + "value": "0x0" }, + "blockHash": null, + "blockNumber": 0, "result": { - "gasUsed": "0x0", + "address": "0x5ac5599fc9df172c89ee7ec55ad9104ccbfed40d", "code": "0x", - "address": "0x5ac5599fc9df172c89ee7ec55ad9104ccbfed40d" + "gasUsed": "0x0" }, + "subtraces": 0, "traceAddress": [ 0 ], - "subtraces": 0, - "transactionPosition": 63, - "transactionHash": "0x60e881fae3884657b5430925c5d0053535b45cce0b8188f2a6be1feee8bcc650", - "blockNumber": 1555170, - "blockHash": "0xea46fbf941d51bf1e4180fbf26d22fda3896f49c7f371d109c226de95dd7b02e" + "transactionHash": null, + "transactionPosition": 0, + "type": "create" } ] } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json index a61e83adcadc..cf891e31b39f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json @@ -1,32 +1,30 @@ { - "genesis": { - "difficulty": "4673862", - "extraData": "0xd683010b05846765746886676f312e3133856c696e7578", - "gasLimit": "9471919", - "hash": "0x7f072150c5905c214966e3432d418910badcdbe510aceaac295b1d7059cc0ffc", + "context": { + "difficulty": "4676144", + "gasLimit": "9481167", "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "mixHash": "0x113ced8fedb939fdc862008da7bdddde726f997c0e6dfba0e55613994757b489", - "nonce": "0x0f411a2e5552c5b7", - "number": "1555284", - "stateRoot": "0x9fe125b361b72d5479b24ad9be9964b74228c73a2dfb0065060a79b4a6dfaa1e", - "timestamp": "1590795374", - "totalDifficulty": "2242642335405", + "number": "1555285", + "timestamp": "1590795378" + }, + "genesis": { "alloc": { - "0xe85df1413eebe1b191c26260e19783a274a6b041": { - "balance": "0x0", - "nonce": "0", - "code": "0x", - "storage": {} - }, "0x877bd459c9b7d8576b44e59e09d076c25946f443": { "balance": "0x6244c985ef1e48e84531", + "code": "0x", "nonce": "265775", + "storage": {} + }, + "0xe85df1413eebe1b191c26260e19783a274a6b041": { + "balance": "0x0", "code": "0x", + "nonce": "0", "storage": {} } }, "config": { + "byzantiumBlock": 0, "chainId": 63, + "constantinopleBlock": 301243, "daoForkSupport": true, "eip150Block": 0, "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", @@ -34,37 +32,39 @@ "eip158Block": 0, "ethash": {}, "homesteadBlock": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 301243, - "petersburgBlock": 999983, - "istanbulBlock": 999983 - } - }, - "context": { - "number": "1555285", - "difficulty": "4676144", - "timestamp": "1590795378", - "gasLimit": "9481167", - "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + "istanbulBlock": 999983, + "petersburgBlock": 999983 + }, + "difficulty": "4673862", + "extraData": "0xd683010b05846765746886676f312e3133856c696e7578", + "gasLimit": "9471919", + "hash": "0x7f072150c5905c214966e3432d418910badcdbe510aceaac295b1d7059cc0ffc", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "mixHash": "0x113ced8fedb939fdc862008da7bdddde726f997c0e6dfba0e55613994757b489", + "nonce": "0x0f411a2e5552c5b7", + "number": "1555284", + "stateRoot": "0x9fe125b361b72d5479b24ad9be9964b74228c73a2dfb0065060a79b4a6dfaa1e", + "timestamp": "1590795374", + "totalDifficulty": "2242642335405" }, "input": "0xf9014083040e2f843b9aca008301aab08080b8eb7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5547f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000037f05581a2a09db45e7846f193471f6d897fb6ff58b7ec41a9c6f63d10aca47d821c365981cba052ec320875625e16141a1a9e8b7993de863698fb699f93ae2cab26149bbb144f", "result": [ { - "type": "create", "action": { "creationMethod": "create", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "value": "0x0", "gas": "0x1aab0", - "init": "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5547f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000037f055" + "init": "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5547f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000037f055", + "value": "0x0" }, + "blockHash": null, + "blockNumber": 0, "error": "out of gas", - "traceAddress": [], "subtraces": 1, - "transactionPosition": 16, - "transactionHash": "0x384487e5ae8d2997aece8e28403d393cb9752425e6de358891bed981c5af1c05", - "blockNumber": 1555285, - "blockHash": "0x93231d8e9662adb4c5c703583a92c7b3112cd5448f43ab4fa1f0f00a0183ed3f" + "traceAddress": [], + "transactionHash": null, + "transactionPosition": 0, + "type": "create" }, { "action": { @@ -74,12 +74,15 @@ "init": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "value": "0xc350" }, + "blockHash": null, + "blockNumber": 0, "error": "insufficient balance for transfer", - "result": {}, "subtraces": 0, "traceAddress": [ 0 ], + "transactionHash": null, + "transactionPosition": 0, "type": "create" } ] diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index 94799609ef5c..d43c4b42440d 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -9,6 +9,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/common/math" "github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core/vm" + "github.com/XinFinOrg/XDPoSChain/params" // Force-load native and js packages, to trigger registration _ "github.com/XinFinOrg/XDPoSChain/eth/tracers/js" @@ -24,6 +25,19 @@ func camel(str string) string { return strings.Join(pieces, "") } +func ensureTracerChainConfig(config *params.ChainConfig) *params.ChainConfig { + defaultTIPTRC21FeeBlock := common.CloneBigInt(params.XDCMainnetChainConfig.TIPTRC21FeeBlock) + if config == nil { + return ¶ms.ChainConfig{TIPTRC21FeeBlock: defaultTIPTRC21FeeBlock} + } + if config.TIPTRC21FeeBlock != nil { + return config + } + clone := *config + clone.TIPTRC21FeeBlock = defaultTIPTRC21FeeBlock + return &clone +} + type callContext struct { Number math.HexOrDecimal64 `json:"number"` Difficulty *math.HexOrDecimal256 `json:"difficulty"` diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 6795721725cf..f2c9520b1c4a 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -251,24 +251,26 @@ func TestTxStartUsesExecutionGasPrice(t *testing.T) { func TestIsPrecompile(t *testing.T) { chaincfg := ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: false, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(100), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(200), - BerlinBlock: big.NewInt(300), - LondonBlock: big.NewInt(0), - Ethash: new(params.EthashConfig), - Clique: nil, + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(100), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(200), + TIPXDCXCancellationFeeBlock: big.NewInt(200), + BerlinBlock: big.NewInt(300), + LondonBlock: big.NewInt(0), + Ethash: new(params.EthashConfig), + Clique: nil, } chaincfg.ByzantiumBlock = big.NewInt(100) chaincfg.IstanbulBlock = big.NewInt(200) + chaincfg.TIPXDCXCancellationFeeBlock = big.NewInt(200) chaincfg.BerlinBlock = big.NewInt(300) txCtx := vm.TxContext{GasPrice: big.NewInt(100000)} tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil, chaincfg) @@ -292,7 +294,7 @@ func TestIsPrecompile(t *testing.T) { t.Error(err) } if string(res) != "true" { - t.Errorf("tracer should consider blake2f as precompile in istanbul") + t.Errorf("tracer should consider blake2f as precompile after TIPXDCXCancellationFee") } } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index fe2764a45148..3df37b4ba74d 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -79,7 +79,7 @@ func BenchmarkTransactionTraceV2(b *testing.B) { evm := vm.NewEVM(context, state, nil, params.AllEthashProtocolChanges, vm.Config{}) - msg, err := core.TransactionToMessage(tx, signer, nil, nil, context.BaseFee) + msg, err := core.TransactionToMessage(tx, signer, nil, nil, context.BaseFee, params.AllEthashProtocolChanges) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 9f8deb41bca7..7df49efce191 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -98,7 +98,6 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block, []common.Hash) { func generateTestChain() (*core.Genesis, []*types.Block, []common.Hash) { chainConfig := *params.AllEthashProtocolChanges - chainConfig.Eip1559Block = big.NewInt(0) // Ensure global chain constants match the test chain config before block generation. common.CopyConstants(chainConfig.ChainID.Uint64()) genesis := &core.Genesis{ diff --git a/ethclient/simulated/backend.go b/ethclient/simulated/backend.go index 10248deaf7d7..00a9805ed2b4 100644 --- a/ethclient/simulated/backend.go +++ b/ethclient/simulated/backend.go @@ -273,6 +273,7 @@ func (b *Backend) rollback(parent *types.Block) { b.pendingBlock = blocks[0] b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database()) + b.pendingState.SetChainConfig(b.config) } // Fork creates a side-chain that can be used to simulate reorgs. @@ -1031,6 +1032,7 @@ func (b *Backend) SendTransaction(ctx context.Context, tx *types.Transaction) er } b.pendingBlock = blocks[0] b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database()) + b.pendingState.SetChainConfig(b.config) b.pendingReceipts = receipts[0] return nil } @@ -1164,6 +1166,7 @@ func (b *Backend) AdjustTime(adjustment time.Duration) error { stateDB, _ := b.blockchain.State() b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database()) + b.pendingState.SetChainConfig(b.config) return nil } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index d342946ac3a9..de6729edeabd 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -736,7 +736,7 @@ func (api *BlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAddres return result, errors.New("undefined XDPoS consensus engine") } } else if api.b.ChainConfig().IsTIPIncreaseMasternodes(block.Number()) { - maxMasternodes = common.MaxMasternodesV2 + maxMasternodes = api.b.ChainConfig().XDPoS.MaxMasternodesV2 } else { maxMasternodes = common.MaxMasternodes } @@ -931,7 +931,7 @@ func (api *BlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.EpochNumb return result, errors.New("undefined XDPoS consensus engine") } } else if api.b.ChainConfig().IsTIPIncreaseMasternodes(block.Number()) { - maxMasternodes = common.MaxMasternodesV2 + maxMasternodes = api.b.ChainConfig().XDPoS.MaxMasternodesV2 } else { maxMasternodes = common.MaxMasternodes } diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 173ae9b06179..5b194406b9ff 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -252,6 +252,7 @@ func newBackendMock() *backendMock { ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), Eip1559Block: big.NewInt(1000), } diff --git a/miner/worker.go b/miner/worker.go index 2ed32a7332b2..8d640cbdb74e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -849,7 +849,7 @@ func (w *worker) commitNewWork() { Extra: w.extra, Time: uint64(tstamp), } - if w.chainConfig.IsDynamicGasLimitBlock(header.Number) { + if w.chainConfig.IsDynamicGasLimit(header.Number) { header.GasLimit = core.CalcGasLimit(parent.GasLimit(), w.config.GasCeil) } else { header.GasLimit = w.config.GasCeil @@ -894,7 +894,7 @@ func (w *worker) commitNewWork() { if w.chainConfig.DAOForkSupport && w.chainConfig.DAOForkBlock != nil && w.chainConfig.DAOForkBlock.Cmp(header.Number) == 0 { misc.ApplyDAOHardFork(work.state) } - if common.TIPSigning.Cmp(header.Number) == 0 { + if w.chainConfig.TIPSigningBlock != nil && w.chainConfig.TIPSigningBlock.Cmp(header.Number) == 0 { work.state.DeleteAddress(common.BlockSignersBinary) } if w.chainConfig.IsPrague(header.Number) { @@ -1100,7 +1100,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr continue } to := tx.To() - if w.header.Number.Uint64() >= common.DenylistHFNumber { + if w.config.IsDenylist(w.header.Number) { from := tx.From() // check if sender is in denylist if common.IsInDenylist(from) { @@ -1115,7 +1115,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr } data := tx.Data() // validate minFee slot for XDCZ - if tx.IsXDCZApplyTransaction() { + if tx.IsXDCZApplyTransaction(w.config) { copyState, _ := bc.State() if err := core.ValidateXDCZApplyTransaction(bc, nil, copyState, common.BytesToAddress(data[4:])); err != nil { log.Debug("XDCZApply: invalid token", "token", common.BytesToAddress(data[4:]).Hex()) @@ -1123,7 +1123,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr } } // validate balance slot, token decimal for XDCX - if tx.IsXDCXApplyTransaction() { + if tx.IsXDCXApplyTransaction(w.config) { copyState, _ := bc.State() if err := core.ValidateXDCXApplyTransaction(bc, nil, copyState, common.BytesToAddress(data[4:])); err != nil { log.Debug("XDCXApply: invalid token", "token", common.BytesToAddress(data[4:]).Hex()) @@ -1186,7 +1186,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr log.Debug("Add Special Transaction failed, account skipped", "hash", hash, "sender", from, "nonce", tx.Nonce(), "to", to, "err", err) } if tokenFeeUsed { - fee := common.GetGasFee(w.header.Number.Uint64(), gas) + fee := common.GetGasFee(w.header.Number.Uint64(), gas, w.config.TIPTRC21FeeBlock, w.config.Gas50xBlock) balanceFee[*to] = new(big.Int).Sub(balanceFee[*to], fee) balanceUpdated[*to] = balanceFee[*to] totalFeeUsed = totalFeeUsed.Add(totalFeeUsed, fee) @@ -1219,7 +1219,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr break } to := tx.To() - if w.header.Number.Uint64() >= common.DenylistHFNumber { + if w.config.IsDenylist(w.header.Number) { from := tx.From() // check if sender is in denylist if common.IsInDenylist(from) { @@ -1236,7 +1236,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr } data := tx.Data() // validate minFee slot for XDCZ - if tx.IsXDCZApplyTransaction() { + if tx.IsXDCZApplyTransaction(w.config) { copyState, _ := bc.State() if err := core.ValidateXDCZApplyTransaction(bc, nil, copyState, common.BytesToAddress(data[4:])); err != nil { log.Debug("XDCZApply: invalid token", "token", common.BytesToAddress(data[4:]).Hex()) @@ -1245,7 +1245,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr } } // validate balance slot, token decimal for XDCX - if tx.IsXDCXApplyTransaction() { + if tx.IsXDCXApplyTransaction(w.config) { copyState, _ := bc.State() if err := core.ValidateXDCXApplyTransaction(bc, nil, copyState, common.BytesToAddress(data[4:])); err != nil { log.Debug("XDCXApply: invalid token", "token", common.BytesToAddress(data[4:]).Hex()) @@ -1317,7 +1317,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr txs.Shift() } if tokenFeeUsed { - fee := common.GetGasFee(w.header.Number.Uint64(), gas) + fee := common.GetGasFee(w.header.Number.Uint64(), gas, w.config.TIPTRC21FeeBlock, w.config.Gas50xBlock) balanceFee[*to] = new(big.Int).Sub(balanceFee[*to], fee) balanceUpdated[*to] = balanceFee[*to] totalFeeUsed = totalFeeUsed.Add(totalFeeUsed, fee) diff --git a/miner/worker_test.go b/miner/worker_test.go index ab901eae53af..c64abea2e42c 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -84,8 +84,10 @@ func TestWorkerUpdateNonXDPoSStaysRunning(t *testing.T) { func TestWorkerCheckPreCommitXDPoSMismatch(t *testing.T) { config := ¶ms.ChainConfig{ - ChainID: big.NewInt(1), + ChainID: big.NewInt(1), + TIPTRC21FeeBlock: big.NewInt(0), XDPoS: ¶ms.XDPoSConfig{ + MaxMasternodesV2: 1, // required to avoid missing fork switch error V2: ¶ms.V2{ SwitchBlock: big.NewInt(0), AllConfigs: map[uint64]*params.V2Config{ diff --git a/params/config.go b/params/config.go index 165436dd559a..ea29824645b8 100644 --- a/params/config.go +++ b/params/config.go @@ -19,6 +19,7 @@ package params import ( "cmp" "encoding/json" + "errors" "fmt" "maps" "math/big" @@ -34,8 +35,49 @@ const ( ConsensusEngineVersion1 = "v1" ConsensusEngineVersion2 = "v2" Default = 0 + + MainnetV2SwitchBlock uint64 = 80370000 // Target 2nd Oct 2024 + TestnetV2SwitchBlock uint64 = 56828700 // Target 13th Nov 2023 + DevnetV2SwitchBlock uint64 = 2700 +) + +var migratedForkFieldJSONKeys = []string{ + "tip2019Block", + "tipSigningBlock", + "tipRandomizeBlock", + "tipIncreaseMasternodesBlock", + "denylistBlock", + "tipNoHalvingMNRewardBlock", + "tipXDCXBlock", + "tipXDCXLendingBlock", + "tipXDCXCancellationFeeBlock", + "tipTRC21FeeBlock", + "berlinBlock", + "londonBlock", + "mergeBlock", + "shanghaiBlock", + "tipXDCXMinerDisableBlock", + "tipXDCXReceiverDisableBlock", + "eip1559Block", + "cancunBlock", + "pragueBlock", + "osakaBlock", + "dynamicGasLimitBlock", + "tipUpgradeRewardBlock", + "tipUpgradePenaltyBlock", + "tipEpochHalvingBlock", +} + +var ( + ErrMissingForkSwitch = errors.New("missing fork switch") + ErrWrongForkSwitchOrder = errors.New("wrong fork switch order") ) +// MigratedForkFieldJSONKeys returns migrated fork JSON keys as a defensive copy. +func MigratedForkFieldJSONKeys() []string { + return append([]string(nil), migratedForkFieldJSONKeys...) +} + var ( MainnetGenesisHash = common.HexToHash("0x4a9d748bd78a8d0385b67788c2435dcdb914f98a96250b68863a1f8b7642d6b1") // XDC Mainnet genesis hash to enforce below configs on TestnetGenesisHash = common.HexToHash("0xbdea512b4f12ff1135ec92c00dc047ffb93890c2ea1aa0eefe9b013d80640075") // XDC Testnet genesis hash to enforce below configs on @@ -167,6 +209,18 @@ var ( }, } + LocalnetV2Configs = map[uint64]*V2Config{ + Default: { + MaxMasternodes: 108, + SwitchRound: 0, + CertThreshold: 0.666, + TimeoutSyncThreshold: 3, + TimeoutPeriod: 10, + MinePeriod: 2, + ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0}, + }, + } + UnitTestV2Configs = map[uint64]*V2Config{ Default: { MaxMasternodes: 18, @@ -206,12 +260,49 @@ var ( // XDPoSChain mainnet config XDCMainnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(50), - HomesteadBlock: big.NewInt(1), - EIP150Block: big.NewInt(2), - EIP155Block: big.NewInt(3), - EIP158Block: big.NewInt(3), - ByzantiumBlock: big.NewInt(4), + Name: "XDCMainnetChainConfig", + ChainID: big.NewInt(50), + HomesteadBlock: big.NewInt(1), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(1), + EIP150Block: big.NewInt(2), + EIP155Block: big.NewInt(3), + EIP158Block: big.NewInt(3), + ByzantiumBlock: big.NewInt(4), + ConstantinopleBlock: nil, + PetersburgBlock: nil, + IstanbulBlock: nil, + TIPSigningBlock: big.NewInt(3000000), + TIPRandomizeBlock: big.NewInt(3464000), + TIPIncreaseMasternodesBlock: big.NewInt(5000000), + DenylistBlock: big.NewInt(38383838), + TIPNoHalvingMNRewardBlock: big.NewInt(38383838), + TIPXDCXBlock: big.NewInt(38383838), + TIPXDCXLendingBlock: big.NewInt(38383838), + TIPXDCXCancellationFeeBlock: big.NewInt(38383838), + TIPTRC21FeeBlock: big.NewInt(38383838), + BerlinBlock: big.NewInt(76321000), + LondonBlock: big.NewInt(76321000), + MergeBlock: big.NewInt(76321000), + ShanghaiBlock: big.NewInt(76321000), + Gas50xBlock: big.NewInt(80370000), + TIPXDCXMinerDisableBlock: big.NewInt(80370000), + TIPXDCXReceiverDisableBlock: big.NewInt(80370900), + Eip1559Block: big.NewInt(98800200), + CancunBlock: big.NewInt(98802000), + PragueBlock: nil, + OsakaBlock: nil, + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: nil, XDPoS: &XDPoSConfig{ Period: 2, Epoch: 900, @@ -219,9 +310,10 @@ var ( RewardCheckpoint: 900, Gap: 450, FoundationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"), + MaxMasternodesV2: 108, V2: &V2{ - SwitchEpoch: common.MainnetConstant.TIPV2SwitchBlock.Uint64() / 900, - SwitchBlock: common.MainnetConstant.TIPV2SwitchBlock, + SwitchEpoch: MainnetV2SwitchBlock / 900, + SwitchBlock: big.NewInt(int64(MainnetV2SwitchBlock)), CurrentConfig: MainnetV2Configs[0], AllConfigs: MainnetV2Configs, }, @@ -230,29 +322,97 @@ var ( // MainnetChainConfig is the chain parameters to run a node on the ethereum main network. MainnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(1150000), - DAOForkBlock: big.NewInt(1920000), - DAOForkSupport: true, - EIP150Block: big.NewInt(2463000), - EIP155Block: big.NewInt(2675000), - EIP158Block: big.NewInt(2675000), - ByzantiumBlock: big.NewInt(4370000), - ConstantinopleBlock: nil, - Ethash: new(EthashConfig), + Name: "MainnetChainConfig", + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(1150000), + DAOForkBlock: big.NewInt(1920000), + DAOForkSupport: true, + TIP2019Block: nil, + EIP150Block: big.NewInt(2463000), + EIP155Block: big.NewInt(2675000), + EIP158Block: big.NewInt(2675000), + ByzantiumBlock: big.NewInt(4370000), + ConstantinopleBlock: nil, + PetersburgBlock: nil, + IstanbulBlock: nil, + TIPSigningBlock: nil, + TIPRandomizeBlock: nil, + TIPIncreaseMasternodesBlock: nil, + DenylistBlock: nil, + TIPNoHalvingMNRewardBlock: nil, + TIPXDCXBlock: nil, + TIPXDCXLendingBlock: nil, + TIPXDCXCancellationFeeBlock: nil, + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: nil, + LondonBlock: nil, + MergeBlock: nil, + ShanghaiBlock: nil, + Gas50xBlock: big.NewInt(80370000), + TIPXDCXMinerDisableBlock: nil, + TIPXDCXReceiverDisableBlock: nil, + Eip1559Block: nil, + CancunBlock: nil, + PragueBlock: nil, + OsakaBlock: nil, + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: new(EthashConfig), + XDPoS: nil, } // TestnetChainConfig contains the chain parameters to run a node on the Apothem testnet. TestnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(51), - HomesteadBlock: big.NewInt(1), - DAOForkBlock: nil, - DAOForkSupport: false, - EIP150Block: big.NewInt(2), - EIP155Block: big.NewInt(3), - EIP158Block: big.NewInt(3), - ByzantiumBlock: big.NewInt(4), - ConstantinopleBlock: nil, + Name: "TestnetChainConfig", + ChainID: big.NewInt(51), + HomesteadBlock: big.NewInt(1), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(1), + EIP150Block: big.NewInt(2), + EIP155Block: big.NewInt(3), + EIP158Block: big.NewInt(3), + ByzantiumBlock: big.NewInt(4), + ConstantinopleBlock: nil, + PetersburgBlock: nil, + IstanbulBlock: nil, + TIPSigningBlock: big.NewInt(3000000), + TIPRandomizeBlock: big.NewInt(3464000), + TIPIncreaseMasternodesBlock: big.NewInt(5000000), + DenylistBlock: big.NewInt(23779191), + TIPNoHalvingMNRewardBlock: big.NewInt(23779191), + TIPXDCXBlock: big.NewInt(23779191), + TIPXDCXLendingBlock: big.NewInt(23779191), + TIPXDCXCancellationFeeBlock: big.NewInt(23779191), + TIPTRC21FeeBlock: big.NewInt(23779191), + Gas50xBlock: big.NewInt(56828700), + BerlinBlock: big.NewInt(61290000), + LondonBlock: big.NewInt(61290000), + MergeBlock: big.NewInt(61290000), + ShanghaiBlock: big.NewInt(61290000), + TIPXDCXMinerDisableBlock: big.NewInt(61290000), + TIPXDCXReceiverDisableBlock: big.NewInt(66825000), + Eip1559Block: big.NewInt(71550000), + CancunBlock: big.NewInt(71551800), + PragueBlock: nil, + OsakaBlock: nil, + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x0E2C88753131CE01c7551B726b28BFD04e44003F"), + XDCXListingSMC: common.HexToAddress("0x14B2Bf043b9c31827A472CE4F94294fE9a6277e0"), + RelayerRegistrationSMC: common.HexToAddress("0xA1996F69f47ba14Cb7f661010A7C31974277958c"), + LendingRegistrationSMC: common.HexToAddress("0x28d7fC2Cf5c18203aaCD7459EFC6Af0643C97bE8"), + Clique: nil, + Ethash: nil, XDPoS: &XDPoSConfig{ Period: 2, Epoch: 900, @@ -260,9 +420,10 @@ var ( RewardCheckpoint: 900, Gap: 450, FoundationWalletAddr: common.HexToAddress("xdc746249c61f5832c5eed53172776b460491bdcd5c"), + MaxMasternodesV2: 15, V2: &V2{ - SwitchEpoch: common.TestnetConstant.TIPV2SwitchBlock.Uint64() / 900, - SwitchBlock: common.TestnetConstant.TIPV2SwitchBlock, + SwitchEpoch: TestnetV2SwitchBlock / 900, + SwitchBlock: big.NewInt(int64(TestnetV2SwitchBlock)), CurrentConfig: TestnetV2Configs[0], AllConfigs: TestnetV2Configs, }, @@ -271,12 +432,49 @@ var ( // DevnetChainConfig contains the chain parameters to run a node on the devnet. DevnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(5551), - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), + Name: "DevnetChainConfig", + ChainID: big.NewInt(5551), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: nil, + PetersburgBlock: nil, + IstanbulBlock: nil, + TIPSigningBlock: big.NewInt(0), + TIPRandomizeBlock: big.NewInt(0), + TIPIncreaseMasternodesBlock: big.NewInt(0), + DenylistBlock: big.NewInt(0), + TIPNoHalvingMNRewardBlock: big.NewInt(0), + TIPXDCXBlock: big.NewInt(0), + TIPXDCXLendingBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + MergeBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(0), + TIPXDCXMinerDisableBlock: big.NewInt(0), + TIPXDCXReceiverDisableBlock: big.NewInt(0), + Eip1559Block: big.NewInt(250000), + CancunBlock: big.NewInt(250000), + PragueBlock: big.NewInt(5000000), + OsakaBlock: nil, + DynamicGasLimitBlock: big.NewInt(5000000), + TIPUpgradeRewardBlock: big.NewInt(5000000), + TIPUpgradePenaltyBlock: big.NewInt(5000000), + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: nil, XDPoS: &XDPoSConfig{ Period: 2, Epoch: 900, @@ -284,39 +482,113 @@ var ( RewardCheckpoint: 900, Gap: 450, FoundationWalletAddr: common.HexToAddress("0x4f288181b1d1aa599c6d7629f1168d46d5f96338"), + MaxMasternodesV2: 108, V2: &V2{ - SwitchEpoch: common.DevnetConstant.TIPV2SwitchBlock.Uint64() / 900, - SwitchBlock: common.DevnetConstant.TIPV2SwitchBlock, + SwitchEpoch: DevnetV2SwitchBlock / 900, + SwitchBlock: big.NewInt(int64(DevnetV2SwitchBlock)), CurrentConfig: DevnetV2Configs[0], AllConfigs: DevnetV2Configs, }, }, } + // LocalnetChainConfig contains the chain parameters to run a node on the local network. + LocalnetChainConfig = &ChainConfig{ + Name: "LocalnetChainConfig", + ChainID: big.NewInt(5151), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: nil, + PetersburgBlock: nil, + IstanbulBlock: nil, + TIPSigningBlock: big.NewInt(0), + TIPRandomizeBlock: big.NewInt(0), + TIPIncreaseMasternodesBlock: big.NewInt(0), + DenylistBlock: big.NewInt(0), + TIPNoHalvingMNRewardBlock: big.NewInt(0), + TIPXDCXBlock: big.NewInt(0), + TIPXDCXLendingBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + MergeBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(0), + TIPXDCXMinerDisableBlock: big.NewInt(0), + TIPXDCXReceiverDisableBlock: big.NewInt(0), + Eip1559Block: big.NewInt(0), + CancunBlock: big.NewInt(0), + PragueBlock: nil, + OsakaBlock: nil, + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: nil, + XDPoS: &XDPoSConfig{ + MaxMasternodesV2: 108, + }, + } + // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. AllEthashProtocolChanges = &ChainConfig{ - ChainID: big.NewInt(1337), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: false, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - ShanghaiBlock: big.NewInt(0), - Eip1559Block: nil, - CancunBlock: nil, - PragueBlock: nil, - OsakaBlock: nil, - Ethash: new(EthashConfig), - Clique: nil, - XDPoS: nil, + Name: "AllEthashProtocolChanges", + ChainID: big.NewInt(1337), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + TIPSigningBlock: big.NewInt(0), + TIPRandomizeBlock: big.NewInt(0), + TIPIncreaseMasternodesBlock: big.NewInt(0), + DenylistBlock: big.NewInt(0), + TIPNoHalvingMNRewardBlock: big.NewInt(0), + TIPXDCXBlock: big.NewInt(0), + TIPXDCXLendingBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + MergeBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(80370000), + TIPXDCXMinerDisableBlock: nil, + TIPXDCXReceiverDisableBlock: nil, + Eip1559Block: big.NewInt(0), + CancunBlock: big.NewInt(0), + PragueBlock: big.NewInt(0), + OsakaBlock: big.NewInt(0), + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: new(EthashConfig), + XDPoS: nil, } // AllDevChainProtocolChanges contains every protocol change (EIPs) introduced @@ -325,32 +597,56 @@ var ( // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. AllDevChainProtocolChanges = &ChainConfig{ - ChainID: big.NewInt(1337), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: false, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - ShanghaiBlock: big.NewInt(0), - Eip1559Block: big.NewInt(0), - CancunBlock: big.NewInt(0), - PragueBlock: big.NewInt(0), - OsakaBlock: big.NewInt(0), - Ethash: nil, - Clique: nil, + Name: "AllDevChainProtocolChanges", + ChainID: big.NewInt(1337), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + TIPSigningBlock: big.NewInt(0), + TIPRandomizeBlock: big.NewInt(0), + TIPIncreaseMasternodesBlock: big.NewInt(0), + DenylistBlock: big.NewInt(0), + TIPNoHalvingMNRewardBlock: big.NewInt(0), + TIPXDCXBlock: big.NewInt(0), + TIPXDCXLendingBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + MergeBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(80370000), + TIPXDCXMinerDisableBlock: nil, + TIPXDCXReceiverDisableBlock: nil, + Eip1559Block: big.NewInt(0), + CancunBlock: big.NewInt(0), + PragueBlock: big.NewInt(0), + OsakaBlock: big.NewInt(0), + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: nil, XDPoS: &XDPoSConfig{ Epoch: 900, Gap: 450, SkipV1Validation: true, FoundationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"), Reward: 250, + MaxMasternodesV2: 108, V2: &V2{ SwitchEpoch: 1, SwitchBlock: big.NewInt(900), @@ -363,48 +659,104 @@ var ( // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. AllCliqueProtocolChanges = &ChainConfig{ - ChainID: big.NewInt(1337), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: false, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - ShanghaiBlock: big.NewInt(0), - Eip1559Block: big.NewInt(0), - CancunBlock: nil, - PragueBlock: nil, - OsakaBlock: nil, - Ethash: nil, - Clique: &CliqueConfig{Period: 0, Epoch: 900}, - XDPoS: nil, + Name: "AllCliqueProtocolChanges", + ChainID: big.NewInt(1337), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + TIPSigningBlock: big.NewInt(0), + TIPRandomizeBlock: big.NewInt(0), + TIPIncreaseMasternodesBlock: big.NewInt(0), + DenylistBlock: big.NewInt(0), + TIPNoHalvingMNRewardBlock: big.NewInt(0), + TIPXDCXBlock: big.NewInt(0), + TIPXDCXLendingBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + MergeBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(80370000), + TIPXDCXMinerDisableBlock: nil, + TIPXDCXReceiverDisableBlock: nil, + Eip1559Block: big.NewInt(0), + CancunBlock: big.NewInt(0), + PragueBlock: big.NewInt(0), + OsakaBlock: big.NewInt(0), + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: &CliqueConfig{Period: 0, Epoch: 900}, + Ethash: nil, + XDPoS: nil, } // XDPoS config with v2 engine after block 901 TestXDPoSMockChainConfig = &ChainConfig{ - ChainID: big.NewInt(1337), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: false, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - Ethash: new(EthashConfig), - Clique: nil, + Name: "TestXDPoSMockChainConfig", + ChainID: big.NewInt(1337), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + TIPSigningBlock: big.NewInt(0), + TIPRandomizeBlock: big.NewInt(0), + TIPIncreaseMasternodesBlock: big.NewInt(0), + DenylistBlock: big.NewInt(0), + TIPNoHalvingMNRewardBlock: big.NewInt(0), + TIPXDCXBlock: big.NewInt(0), + TIPXDCXLendingBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + MergeBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(80370000), + TIPXDCXMinerDisableBlock: nil, + TIPXDCXReceiverDisableBlock: nil, + Eip1559Block: big.NewInt(0), + CancunBlock: big.NewInt(0), + PragueBlock: big.NewInt(0), + OsakaBlock: big.NewInt(0), + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: new(EthashConfig), XDPoS: &XDPoSConfig{ Epoch: 900, Gap: 450, SkipV1Validation: true, FoundationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"), Reward: 250, + MaxMasternodesV2: 108, V2: &V2{ SwitchEpoch: 1, SwitchBlock: big.NewInt(900), @@ -417,54 +769,101 @@ var ( // TestChainConfig contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers for testing purposes. TestChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: false, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - ShanghaiBlock: big.NewInt(0), - Eip1559Block: nil, - CancunBlock: nil, - PragueBlock: nil, - OsakaBlock: nil, - Ethash: new(EthashConfig), - Clique: nil, - XDPoS: nil, + Name: "TestChainConfig", + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + TIPSigningBlock: big.NewInt(0), + TIPRandomizeBlock: big.NewInt(0), + TIPIncreaseMasternodesBlock: big.NewInt(0), + DenylistBlock: big.NewInt(0), + TIPNoHalvingMNRewardBlock: big.NewInt(0), + TIPXDCXBlock: big.NewInt(0), + TIPXDCXLendingBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + MergeBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(80370000), + TIPXDCXMinerDisableBlock: nil, + TIPXDCXReceiverDisableBlock: nil, + Eip1559Block: big.NewInt(0), + CancunBlock: big.NewInt(0), + PragueBlock: big.NewInt(0), + OsakaBlock: big.NewInt(0), + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: new(EthashConfig), + XDPoS: nil, } // MergedTestChainConfig contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers for testing purposes. MergedTestChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: false, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - ShanghaiBlock: big.NewInt(0), - Eip1559Block: big.NewInt(0), - CancunBlock: big.NewInt(0), - PragueBlock: big.NewInt(0), - OsakaBlock: big.NewInt(0), - Ethash: new(EthashConfig), - Clique: nil, - XDPoS: nil, + Name: "MergedTestChainConfig", + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + TIP2019Block: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + TIPSigningBlock: big.NewInt(0), + TIPRandomizeBlock: big.NewInt(0), + TIPIncreaseMasternodesBlock: big.NewInt(0), + DenylistBlock: big.NewInt(0), + TIPNoHalvingMNRewardBlock: big.NewInt(0), + TIPXDCXBlock: big.NewInt(0), + TIPXDCXLendingBlock: big.NewInt(0), + TIPXDCXCancellationFeeBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + MergeBlock: big.NewInt(0), + ShanghaiBlock: big.NewInt(0), + Gas50xBlock: big.NewInt(80370000), + TIPXDCXMinerDisableBlock: nil, + TIPXDCXReceiverDisableBlock: nil, + Eip1559Block: big.NewInt(0), + CancunBlock: big.NewInt(0), + PragueBlock: big.NewInt(0), + OsakaBlock: big.NewInt(0), + DynamicGasLimitBlock: nil, + TIPUpgradeRewardBlock: nil, + TIPUpgradePenaltyBlock: nil, + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: new(EthashConfig), + XDPoS: nil, } + TestRules = TestChainConfig.Rules(new(big.Int)) ) @@ -500,12 +899,37 @@ type ChainConfig struct { PragueBlock *big.Int `json:"pragueBlock,omitempty"` OsakaBlock *big.Int `json:"osakaBlock,omitempty"` - DynamicGasLimitBlock *big.Int `json:"dynamicGasLimitBlock,omitempty"` // Dynamic gas limit adjustment algorithm activation block (nil = no fork) + TIP2019Block *big.Int `json:"tip2019Block,omitempty"` + TIPSigningBlock *big.Int `json:"tipSigningBlock,omitempty"` + TIPRandomizeBlock *big.Int `json:"tipRandomizeBlock,omitempty"` + TIPIncreaseMasternodesBlock *big.Int `json:"tipIncreaseMasternodesBlock,omitempty"` + DenylistBlock *big.Int `json:"denylistBlock,omitempty"` + TIPNoHalvingMNRewardBlock *big.Int `json:"tipNoHalvingMNRewardBlock,omitempty"` + TIPXDCXBlock *big.Int `json:"tipXDCXBlock,omitempty"` + TIPXDCXLendingBlock *big.Int `json:"tipXDCXLendingBlock,omitempty"` + TIPXDCXCancellationFeeBlock *big.Int `json:"tipXDCXCancellationFeeBlock,omitempty"` + TIPTRC21FeeBlock *big.Int `json:"tipTRC21FeeBlock,omitempty"` + Gas50xBlock *big.Int `json:"gas50xBlock,omitempty"` + TIPXDCXMinerDisableBlock *big.Int `json:"tipXDCXMinerDisableBlock,omitempty"` + TIPXDCXReceiverDisableBlock *big.Int `json:"tipXDCXReceiverDisableBlock,omitempty"` + DynamicGasLimitBlock *big.Int `json:"dynamicGasLimitBlock,omitempty"` + TIPUpgradeRewardBlock *big.Int `json:"tipUpgradeRewardBlock,omitempty"` + TIPUpgradePenaltyBlock *big.Int `json:"tipUpgradePenaltyBlock,omitempty"` + TIPEpochHalvingBlock *big.Int `json:"tipEpochHalvingBlock,omitempty"` + + TRC21IssuerSMC common.Address `json:"trc21IssuerSMC,omitempty"` + XDCXListingSMC common.Address `json:"xdcxListingSMC,omitempty"` + RelayerRegistrationSMC common.Address `json:"relayerRegistrationSMC,omitempty"` + LendingRegistrationSMC common.Address `json:"lendingRegistrationSMC,omitempty"` // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` XDPoS *XDPoSConfig `json:"XDPoS,omitempty"` + + Name string `json:"-"` + jsonPresence map[string]struct{} `json:"-"` + jsonPresenceTracked bool `json:"-"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -535,19 +959,49 @@ type XDPoSConfig struct { RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards. Gap uint64 `json:"gap"` // Gap time preparing for the next epoch FoundationWalletAddr common.Address `json:"foundationWalletAddr"` // Foundation Address Wallet + MaxMasternodesV2 int `json:"maxMasternodesV2"` // Last v1 masternodes after TIPIncrease SkipV1Validation bool //Skip Block Validation for testing purpose, V1 consensus only V2 *V2 `json:"v2"` + + jsonPresence map[string]struct{} `json:"-"` + jsonPresenceTracked bool `json:"-"` +} + +// UnmarshalJSON captures field presence so strict missing-field backfill can +// distinguish omitted keys from explicit zero-values. +func (c *ChainConfig) UnmarshalJSON(data []byte) error { + type chainConfigAlias ChainConfig + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + var decoded chainConfigAlias + if err := json.Unmarshal(data, &decoded); err != nil { + return err + } + *c = ChainConfig(decoded) + c.jsonPresenceTracked = true + c.jsonPresence = make(map[string]struct{}, len(raw)) + for key := range raw { + c.jsonPresence[key] = struct{}{} + } + return nil } // UnmarshalJSON supports both the current and legacy typo-ed JSON key for // foundation wallet address to keep old on-disk chain configs compatible. func (c *XDPoSConfig) UnmarshalJSON(data []byte) error { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } type xdpJSON struct { Period uint64 `json:"period"` Epoch uint64 `json:"epoch"` Reward uint64 `json:"reward"` RewardCheckpoint uint64 `json:"rewardCheckpoint"` Gap uint64 `json:"gap"` + MaxMasternodesV2 int `json:"maxMasternodesV2"` FoundationWalletAddr common.Address `json:"foundationWalletAddr"` LegacyFoudationWalletAddr common.Address `json:"foudationWalletAddr"` SkipV1Validation bool `json:"SkipV1Validation"` @@ -563,12 +1017,18 @@ func (c *XDPoSConfig) UnmarshalJSON(data []byte) error { c.Reward = decoded.Reward c.RewardCheckpoint = decoded.RewardCheckpoint c.Gap = decoded.Gap + c.MaxMasternodesV2 = decoded.MaxMasternodesV2 c.FoundationWalletAddr = decoded.FoundationWalletAddr if c.FoundationWalletAddr == (common.Address{}) && decoded.LegacyFoudationWalletAddr != (common.Address{}) { c.FoundationWalletAddr = decoded.LegacyFoudationWalletAddr } c.SkipV1Validation = decoded.SkipV1Validation c.V2 = decoded.V2 + c.jsonPresenceTracked = true + c.jsonPresence = make(map[string]struct{}, len(raw)) + for key := range raw { + c.jsonPresence[key] = struct{}{} + } return nil } @@ -580,7 +1040,7 @@ type V2 struct { SwitchBlock *big.Int `json:"switchBlock"` CurrentConfig *V2Config `json:"config"` AllConfigs map[uint64]*V2Config `json:"allConfigs"` - configIndex []uint64 //list of switch block of configs + configIndex []uint64 // list of switch block of configs } type V2Config struct { @@ -609,6 +1069,268 @@ type ExpTimeoutConfig struct { MaxExponent uint8 `json:"maxExponent"` // max exponent in base^exponent } +// Clone returns an independent copy of the v2 config. +func (c *V2Config) Clone() *V2Config { + if c == nil { + return nil + } + clone := *c + return &clone +} + +// Clone returns a read-locked deep copy of the V2 state. +func (v2 *V2) Clone() *V2 { + if v2 == nil { + return nil + } + v2.lock.RLock() + defer v2.lock.RUnlock() + + clone := &V2{ + SwitchEpoch: v2.SwitchEpoch, + SwitchBlock: common.CloneBigInt(v2.SwitchBlock), + } + if v2.CurrentConfig != nil { + clone.CurrentConfig = v2.CurrentConfig.Clone() + } + if v2.AllConfigs != nil { + clone.AllConfigs = make(map[uint64]*V2Config, len(v2.AllConfigs)) + for key, cfg := range v2.AllConfigs { + clone.AllConfigs[key] = cfg.Clone() + } + } + if v2.configIndex != nil { + clone.configIndex = append([]uint64(nil), v2.configIndex...) + } + return clone +} + +// Clone returns an independent copy of the XDPoS config. +func (c *XDPoSConfig) Clone() *XDPoSConfig { + if c == nil { + return nil + } + clone := *c + clone.V2 = c.V2.Clone() + if c.jsonPresence != nil { + clone.jsonPresence = make(map[string]struct{}, len(c.jsonPresence)) + for key := range c.jsonPresence { + clone.jsonPresence[key] = struct{}{} + } + } + return &clone +} + +// Clone returns a deep copy of the chain config and nested consensus configs. +func (c *ChainConfig) Clone() *ChainConfig { + if c == nil { + return nil + } + clone := *c + clone.ChainID = common.CloneBigInt(c.ChainID) + clone.HomesteadBlock = common.CloneBigInt(c.HomesteadBlock) + clone.TIP2019Block = common.CloneBigInt(c.TIP2019Block) + clone.DAOForkBlock = common.CloneBigInt(c.DAOForkBlock) + clone.EIP150Block = common.CloneBigInt(c.EIP150Block) + clone.EIP155Block = common.CloneBigInt(c.EIP155Block) + clone.EIP158Block = common.CloneBigInt(c.EIP158Block) + clone.ByzantiumBlock = common.CloneBigInt(c.ByzantiumBlock) + clone.ConstantinopleBlock = common.CloneBigInt(c.ConstantinopleBlock) + clone.PetersburgBlock = common.CloneBigInt(c.PetersburgBlock) + clone.IstanbulBlock = common.CloneBigInt(c.IstanbulBlock) + clone.TIPSigningBlock = common.CloneBigInt(c.TIPSigningBlock) + clone.TIPRandomizeBlock = common.CloneBigInt(c.TIPRandomizeBlock) + clone.TIPIncreaseMasternodesBlock = common.CloneBigInt(c.TIPIncreaseMasternodesBlock) + clone.DenylistBlock = common.CloneBigInt(c.DenylistBlock) + clone.TIPNoHalvingMNRewardBlock = common.CloneBigInt(c.TIPNoHalvingMNRewardBlock) + clone.TIPXDCXBlock = common.CloneBigInt(c.TIPXDCXBlock) + clone.TIPXDCXLendingBlock = common.CloneBigInt(c.TIPXDCXLendingBlock) + clone.TIPXDCXCancellationFeeBlock = common.CloneBigInt(c.TIPXDCXCancellationFeeBlock) + clone.TIPTRC21FeeBlock = common.CloneBigInt(c.TIPTRC21FeeBlock) + clone.BerlinBlock = common.CloneBigInt(c.BerlinBlock) + clone.LondonBlock = common.CloneBigInt(c.LondonBlock) + clone.MergeBlock = common.CloneBigInt(c.MergeBlock) + clone.ShanghaiBlock = common.CloneBigInt(c.ShanghaiBlock) + clone.Gas50xBlock = common.CloneBigInt(c.Gas50xBlock) + clone.TIPXDCXMinerDisableBlock = common.CloneBigInt(c.TIPXDCXMinerDisableBlock) + clone.TIPXDCXReceiverDisableBlock = common.CloneBigInt(c.TIPXDCXReceiverDisableBlock) + clone.Eip1559Block = common.CloneBigInt(c.Eip1559Block) + clone.CancunBlock = common.CloneBigInt(c.CancunBlock) + clone.PragueBlock = common.CloneBigInt(c.PragueBlock) + clone.OsakaBlock = common.CloneBigInt(c.OsakaBlock) + clone.DynamicGasLimitBlock = common.CloneBigInt(c.DynamicGasLimitBlock) + clone.TIPUpgradeRewardBlock = common.CloneBigInt(c.TIPUpgradeRewardBlock) + clone.TIPUpgradePenaltyBlock = common.CloneBigInt(c.TIPUpgradePenaltyBlock) + clone.TIPEpochHalvingBlock = common.CloneBigInt(c.TIPEpochHalvingBlock) + clone.TRC21IssuerSMC = c.TRC21IssuerSMC + clone.XDCXListingSMC = c.XDCXListingSMC + clone.RelayerRegistrationSMC = c.RelayerRegistrationSMC + clone.LendingRegistrationSMC = c.LendingRegistrationSMC + if c.Clique != nil { + clique := *c.Clique + clone.Clique = &clique + } + if c.Ethash != nil { + clone.Ethash = new(EthashConfig) + } + clone.XDPoS = c.XDPoS.Clone() + if c.jsonPresence != nil { + clone.jsonPresence = make(map[string]struct{}, len(c.jsonPresence)) + for key := range c.jsonPresence { + clone.jsonPresence[key] = struct{}{} + } + } + return &clone +} + +func GetBuiltInChainConfigByHash(ghash common.Hash) *ChainConfig { + switch ghash { + case MainnetGenesisHash: + return XDCMainnetChainConfig + case TestnetGenesisHash: + return TestnetChainConfig + case DevnetGenesisHash: + return DevnetChainConfig + default: + return nil + } +} + +func isBuiltInTestNetwork(chainID *big.Int) bool { + switch chainID.Uint64() { + case TestnetChainConfig.ChainID.Uint64(): + return true + case 1: // MainnetChainConfig, TestChainConfig, MergedTestChainConfig + return true + case 1337: // AllEthashProtocolChanges, AllDevChainProtocolChanges, AllCliqueProtocolChanges, TestXDPoSMockChainConfig + return true + default: + return false + } +} + +// CheckConfigForkOrder checks that we don't "skip" any forks, geth isn't pluggable enough +// to guarantee that forks can be implemented in a different order than on official networks +func (c *ChainConfig) CheckConfigForkOrder() error { + if c.ChainID == nil { + return fmt.Errorf("invalid chain config: %w %s", ErrMissingForkSwitch, "ChainID") + } + if c.TIPTRC21FeeBlock == nil { + return fmt.Errorf("invalid chain config: %w %s", ErrMissingForkSwitch, "TIPTRC21FeeBlock") + } + if c.Gas50xBlock != nil && c.Gas50xBlock.Cmp(c.TIPTRC21FeeBlock) < 0 { + return fmt.Errorf("invalid chain config: %w TIPTRC21FeeBlock %v > Gas50xBlock %v", ErrWrongForkSwitchOrder, c.TIPTRC21FeeBlock, c.Gas50xBlock) + } + if c.XDPoS == nil && c.Ethash == nil && c.Clique == nil && !isBuiltInTestNetwork(c.ChainID) { + return fmt.Errorf("invalid chain config: %w %s", ErrMissingForkSwitch, "XDPoS") + } + if c.XDPoS != nil { + if c.XDPoS.MaxMasternodesV2 == 0 { + return fmt.Errorf("invalid chain config: %w %s", ErrMissingForkSwitch, "XDPoS.MaxMasternodesV2") + } + } + return nil +} + +func (c *ChainConfig) isJSONFieldMissing(key string, fallback bool) bool { + if c == nil { + return false + } + if !c.jsonPresenceTracked { + return fallback + } + _, ok := c.jsonPresence[key] + return !ok +} + +// BackfillMissingFields copies missing fields from LocalnetChainConfig into c +// using strict JSON-key presence when available. If presence metadata is +// unavailable, pointer-nil/zero-value fallbacks are used for compatibility. +func (c *ChainConfig) BackfillMissingFields() *ChainConfig { + if c == nil { + return c + } + + dest := c.Clone() + src := LocalnetChainConfig + + bigIntFields := []struct { + key string + dst **big.Int + src *big.Int + }{ + {"chainId", &dest.ChainID, src.ChainID}, + {"homesteadBlock", &dest.HomesteadBlock, src.HomesteadBlock}, + {"daoForkBlock", &dest.DAOForkBlock, src.DAOForkBlock}, + {"eip150Block", &dest.EIP150Block, src.EIP150Block}, + {"eip155Block", &dest.EIP155Block, src.EIP155Block}, + {"eip158Block", &dest.EIP158Block, src.EIP158Block}, + {"byzantiumBlock", &dest.ByzantiumBlock, src.ByzantiumBlock}, + {"constantinopleBlock", &dest.ConstantinopleBlock, src.ConstantinopleBlock}, + {"petersburgBlock", &dest.PetersburgBlock, src.PetersburgBlock}, + {"istanbulBlock", &dest.IstanbulBlock, src.IstanbulBlock}, + {"tip2019Block", &dest.TIP2019Block, src.TIP2019Block}, + {"tipSigningBlock", &dest.TIPSigningBlock, src.TIPSigningBlock}, + {"tipRandomizeBlock", &dest.TIPRandomizeBlock, src.TIPRandomizeBlock}, + {"tipIncreaseMasternodesBlock", &dest.TIPIncreaseMasternodesBlock, src.TIPIncreaseMasternodesBlock}, + {"denylistBlock", &dest.DenylistBlock, src.DenylistBlock}, + {"tipNoHalvingMNRewardBlock", &dest.TIPNoHalvingMNRewardBlock, src.TIPNoHalvingMNRewardBlock}, + {"tipXDCXBlock", &dest.TIPXDCXBlock, src.TIPXDCXBlock}, + {"tipXDCXLendingBlock", &dest.TIPXDCXLendingBlock, src.TIPXDCXLendingBlock}, + {"tipXDCXCancellationFeeBlock", &dest.TIPXDCXCancellationFeeBlock, src.TIPXDCXCancellationFeeBlock}, + {"tipTRC21FeeBlock", &dest.TIPTRC21FeeBlock, src.TIPTRC21FeeBlock}, + {"gas50xBlock", &dest.Gas50xBlock, src.Gas50xBlock}, + {"berlinBlock", &dest.BerlinBlock, src.BerlinBlock}, + {"londonBlock", &dest.LondonBlock, src.LondonBlock}, + {"mergeBlock", &dest.MergeBlock, src.MergeBlock}, + {"shanghaiBlock", &dest.ShanghaiBlock, src.ShanghaiBlock}, + {"tipXDCXMinerDisableBlock", &dest.TIPXDCXMinerDisableBlock, src.TIPXDCXMinerDisableBlock}, + {"tipXDCXReceiverDisableBlock", &dest.TIPXDCXReceiverDisableBlock, src.TIPXDCXReceiverDisableBlock}, + {"eip1559Block", &dest.Eip1559Block, src.Eip1559Block}, + {"cancunBlock", &dest.CancunBlock, src.CancunBlock}, + {"pragueBlock", &dest.PragueBlock, src.PragueBlock}, + {"osakaBlock", &dest.OsakaBlock, src.OsakaBlock}, + {"dynamicGasLimitBlock", &dest.DynamicGasLimitBlock, src.DynamicGasLimitBlock}, + {"tipUpgradeRewardBlock", &dest.TIPUpgradeRewardBlock, src.TIPUpgradeRewardBlock}, + {"tipUpgradePenaltyBlock", &dest.TIPUpgradePenaltyBlock, src.TIPUpgradePenaltyBlock}, + {"tipEpochHalvingBlock", &dest.TIPEpochHalvingBlock, src.TIPEpochHalvingBlock}, + } + + addressFields := []struct { + key string + dst *common.Address + src common.Address + }{ + {"trc21IssuerSMC", &dest.TRC21IssuerSMC, src.TRC21IssuerSMC}, + {"xdcxListingSMC", &dest.XDCXListingSMC, src.XDCXListingSMC}, + {"relayerRegistrationSMC", &dest.RelayerRegistrationSMC, src.RelayerRegistrationSMC}, + {"lendingRegistrationSMC", &dest.LendingRegistrationSMC, src.LendingRegistrationSMC}, + } + + for _, field := range bigIntFields { + if dest.isJSONFieldMissing(field.key, *field.dst == nil) { + log.Info("Backfilled missing field", "field", field.key, "old", *field.dst, "new", field.src) + *field.dst = common.CloneBigInt(field.src) + } + } + + for _, field := range addressFields { + if dest.isJSONFieldMissing(field.key, *field.dst == (common.Address{})) { + log.Info("Backfilled missing field", "field", field.key, "old", field.dst.Hex(), "new", field.src.Hex()) + *field.dst = field.src + } + } + + if dest.XDPoS == nil { + log.Warn("XDPoS in source chain config is nil") + } else if dest.XDPoS.MaxMasternodesV2 == 0 { + log.Info("Backfilled missing field", "field", "XDPoS.MaxMasternodesV2", "old", 0, "new", src.XDPoS.MaxMasternodesV2) + dest.XDPoS.MaxMasternodesV2 = src.XDPoS.MaxMasternodesV2 + } + + return dest +} + func XDPoSConfigEqual(a, b *XDPoSConfig) bool { if a == nil || b == nil { if a != b { @@ -641,6 +1363,10 @@ func XDPoSConfigEqual(a, b *XDPoSConfig) bool { log.Warn("[XDPoSConfigEqual] FoundationWalletAddr mismatch", "a.FoundationWalletAddr", a.FoundationWalletAddr.Hex(), "b.FoundationWalletAddr", b.FoundationWalletAddr.Hex()) return false } + if a.MaxMasternodesV2 != b.MaxMasternodesV2 { + log.Warn("[XDPoSConfigEqual] MaxMasternodesV2 mismatch", "a.MaxMasternodesV2", a.MaxMasternodesV2, "b.MaxMasternodesV2", b.MaxMasternodesV2) + return false + } if a.SkipV1Validation != b.SkipV1Validation { log.Warn("[XDPoSConfigEqual] SkipV1Validation mismatch", "a.SkipV1Validation", a.SkipV1Validation, "b.SkipV1Validation", b.SkipV1Validation) return false @@ -699,7 +1425,7 @@ func (c *XDPoSConfig) String() string { return "XDPoSConfig: " } - return fmt.Sprintf("XDPoSConfig{Period: %v, Epoch: %v, Reward: %v, RewardCheckpoint: %v, Gap: %v, FoundationWalletAddr: %v, SkipV1Validation: %v, V2: %s}", c.Period, c.Epoch, c.Reward, c.RewardCheckpoint, c.Gap, c.FoundationWalletAddr.String0x(), c.SkipV1Validation, c.V2.String()) + return fmt.Sprintf("XDPoSConfig{Period: %v, Epoch: %v, Reward: %v, RewardCheckpoint: %v, Gap: %v, MaxMasternodesV2: %v, FoundationWalletAddr: %v, SkipV1Validation: %v, V2: %s}", c.Period, c.Epoch, c.Reward, c.RewardCheckpoint, c.Gap, c.MaxMasternodesV2, c.FoundationWalletAddr.String0x(), c.SkipV1Validation, c.V2.String()) } // Description returns a human-readable description of XDPoSConfig @@ -716,6 +1442,7 @@ func (c *XDPoSConfig) Description(indent int) string { banner += fmt.Sprintf("%s- Reward: %v\n", prefix, c.Reward) banner += fmt.Sprintf("%s- RewardCheckpoint: %v\n", prefix, c.RewardCheckpoint) banner += fmt.Sprintf("%s- Gap: %v\n", prefix, c.Gap) + banner += fmt.Sprintf("%s- MaxMasternodesV2: %v\n", prefix, c.MaxMasternodesV2) banner += fmt.Sprintf("%s- FoundationWalletAddr: %v\n", prefix, c.FoundationWalletAddr.Hex()) banner += fmt.Sprintf("%s- SkipV1Validation: %v\n", prefix, c.SkipV1Validation) banner += fmt.Sprintf("%s- %s", prefix, c.V2.Description(indent+2)) @@ -856,7 +1583,13 @@ func (v2 *V2) BuildConfigIndex() { } func (v2 *V2) ConfigIndex() []uint64 { - return v2.configIndex + v2.lock.RLock() + defer v2.lock.RUnlock() + + if v2.configIndex == nil { + return nil + } + return append([]uint64(nil), v2.configIndex...) } // String implements the fmt.Stringer interface, returning a string representation @@ -866,55 +1599,128 @@ func (c *ChainConfig) String() string { // Add block-based forks if c.HomesteadBlock != nil { - result += fmt.Sprintf(", HomesteadBlock: %v", c.HomesteadBlock) + result += fmt.Sprintf(", Homestead: %v", c.HomesteadBlock) + } + if c.TIP2019Block != nil { + result += fmt.Sprintf(", TIP2019: %v", c.TIP2019Block) } if c.DAOForkBlock != nil { - result += fmt.Sprintf(", DAOForkBlock: %v", c.DAOForkBlock) + result += fmt.Sprintf(", DAOFork: %v", c.DAOForkBlock) } + result += fmt.Sprintf(", DAOForkSupport: %v", c.DAOForkSupport) if c.EIP150Block != nil { - result += fmt.Sprintf(", EIP150Block: %v", c.EIP150Block) + result += fmt.Sprintf(", EIP150: %v", c.EIP150Block) } if c.EIP155Block != nil { - result += fmt.Sprintf(", EIP155Block: %v", c.EIP155Block) + result += fmt.Sprintf(", EIP155: %v", c.EIP155Block) } if c.EIP158Block != nil { - result += fmt.Sprintf(", EIP158Block: %v", c.EIP158Block) + result += fmt.Sprintf(", EIP158: %v", c.EIP158Block) } if c.ByzantiumBlock != nil { - result += fmt.Sprintf(", ByzantiumBlock: %v", c.ByzantiumBlock) + result += fmt.Sprintf(", Byzantium: %v", c.ByzantiumBlock) } if c.ConstantinopleBlock != nil { - result += fmt.Sprintf(", ConstantinopleBlock: %v", c.ConstantinopleBlock) + result += fmt.Sprintf(", Constantinople: %v", c.ConstantinopleBlock) } if c.PetersburgBlock != nil { - result += fmt.Sprintf(", PetersburgBlock: %v", c.PetersburgBlock) + result += fmt.Sprintf(", Petersburg: %v", c.PetersburgBlock) } if c.IstanbulBlock != nil { - result += fmt.Sprintf(", IstanbulBlock: %v", c.IstanbulBlock) + result += fmt.Sprintf(", Istanbul: %v", c.IstanbulBlock) + } + if c.TIPSigningBlock != nil { + result += fmt.Sprintf(", TIPSigning: %v", c.TIPSigningBlock) + } + if c.TIPRandomizeBlock != nil { + result += fmt.Sprintf(", TIPRandomize: %v", c.TIPRandomizeBlock) + } + if c.TIPIncreaseMasternodesBlock != nil { + result += fmt.Sprintf(", TIPIncreaseMasternodes: %v", c.TIPIncreaseMasternodesBlock) + } + if c.DenylistBlock != nil { + result += fmt.Sprintf(", Denylist: %v", c.DenylistBlock) + } + if c.TIPNoHalvingMNRewardBlock != nil { + result += fmt.Sprintf(", TIPNoHalvingMNReward: %v", c.TIPNoHalvingMNRewardBlock) + } + if c.TIPXDCXBlock != nil { + result += fmt.Sprintf(", TIPXDCX: %v", c.TIPXDCXBlock) + } + if c.TIPXDCXLendingBlock != nil { + result += fmt.Sprintf(", TIPXDCXLending: %v", c.TIPXDCXLendingBlock) + } + if c.TIPXDCXCancellationFeeBlock != nil { + result += fmt.Sprintf(", TIPXDCXCancellationFee: %v", c.TIPXDCXCancellationFeeBlock) + } + if c.TIPTRC21FeeBlock != nil { + result += fmt.Sprintf(", TIPTRC21Fee: %v", c.TIPTRC21FeeBlock) } if c.BerlinBlock != nil { - result += fmt.Sprintf(", BerlinBlock: %v", c.BerlinBlock) + result += fmt.Sprintf(", Berlin: %v", c.BerlinBlock) } if c.LondonBlock != nil { - result += fmt.Sprintf(", LondonBlock: %v", c.LondonBlock) + result += fmt.Sprintf(", London: %v", c.LondonBlock) } if c.MergeBlock != nil { - result += fmt.Sprintf(", MergeBlock: %v", c.MergeBlock) + result += fmt.Sprintf(", Merge: %v", c.MergeBlock) } if c.ShanghaiBlock != nil { - result += fmt.Sprintf(", ShanghaiBlock: %v", c.ShanghaiBlock) + result += fmt.Sprintf(", Shanghai: %v", c.ShanghaiBlock) + } + if c.Gas50xBlock != nil { + result += fmt.Sprintf(", Gas50x: %v", c.Gas50xBlock) + } + if c.TIPXDCXMinerDisableBlock != nil { + result += fmt.Sprintf(", TIPXDCXMinerDisable: %v", c.TIPXDCXMinerDisableBlock) + } + if c.TIPXDCXReceiverDisableBlock != nil { + result += fmt.Sprintf(", TIPXDCXReceiverDisable: %v", c.TIPXDCXReceiverDisableBlock) + } + if c.Eip1559Block != nil { + result += fmt.Sprintf(", Eip1559: %v", c.Eip1559Block) } if c.CancunBlock != nil { - result += fmt.Sprintf(", CancunBlock: %v", c.CancunBlock) + result += fmt.Sprintf(", Cancun: %v", c.CancunBlock) } if c.PragueBlock != nil { - result += fmt.Sprintf(", PragueBlock: %v", c.PragueBlock) + result += fmt.Sprintf(", Prague: %v", c.PragueBlock) + } + if c.OsakaBlock != nil { + result += fmt.Sprintf(", Osaka: %v", c.OsakaBlock) } if c.DynamicGasLimitBlock != nil { - result += fmt.Sprintf(", DynamicGasLimitBlock: %v", c.DynamicGasLimitBlock) + result += fmt.Sprintf(", DynamicGasLimit: %v", c.DynamicGasLimitBlock) + } + if c.TIPUpgradeRewardBlock != nil { + result += fmt.Sprintf(", TIPUpgradeReward: %v", c.TIPUpgradeRewardBlock) + } + if c.TIPUpgradePenaltyBlock != nil { + result += fmt.Sprintf(", TIPUpgradePenalty: %v", c.TIPUpgradePenaltyBlock) + } + if c.TIPEpochHalvingBlock != nil { + result += fmt.Sprintf(", TIPEpochHalving: %v", c.TIPEpochHalvingBlock) + } + if c.TRC21IssuerSMC != (common.Address{}) { + result += fmt.Sprintf(", TRC21IssuerSMC: %s", c.TRC21IssuerSMC.Hex()) + } + if c.XDCXListingSMC != (common.Address{}) { + result += fmt.Sprintf(", XDCXListingSMC: %s", c.XDCXListingSMC.Hex()) + } + if c.RelayerRegistrationSMC != (common.Address{}) { + result += fmt.Sprintf(", RelayerRegistrationSMC: %s", c.RelayerRegistrationSMC.Hex()) + } + if c.LendingRegistrationSMC != (common.Address{}) { + result += fmt.Sprintf(", LendingRegistrationSMC: %s", c.LendingRegistrationSMC.Hex()) + } + if c.Ethash != nil { + result += fmt.Sprintf(", Ethash: %s", c.Ethash.String()) + } + if c.Clique != nil { + result += fmt.Sprintf(", Clique: %s", c.Clique.String()) } if c.XDPoS != nil { - result += fmt.Sprintf(", %s", c.XDPoS.String()) + result += fmt.Sprintf(", XDPoS: %s", c.XDPoS.String()) } result += "}" return result @@ -932,79 +1738,46 @@ func (c *ChainConfig) Description() string { default: engine = "unknown" } - berlinBlock := common.BerlinBlock - if c.BerlinBlock != nil { - berlinBlock = c.BerlinBlock - } - londonBlock := common.LondonBlock - if c.LondonBlock != nil { - londonBlock = c.LondonBlock - } - mergeBlock := common.MergeBlock - if c.MergeBlock != nil { - mergeBlock = c.MergeBlock - } - shanghaiBlock := common.ShanghaiBlock - if c.ShanghaiBlock != nil { - shanghaiBlock = c.ShanghaiBlock - } - eip1559Block := common.Eip1559Block - if c.Eip1559Block != nil { - eip1559Block = c.Eip1559Block - } - cancunBlock := common.CancunBlock - if c.CancunBlock != nil { - cancunBlock = c.CancunBlock - } - pragueBlock := common.PragueBlock - if c.PragueBlock != nil { - pragueBlock = c.PragueBlock - } - osakaBlock := common.OsakaBlock - if c.OsakaBlock != nil { - osakaBlock = c.OsakaBlock - } - dynamicGasLimitBlock := common.DynamicGasLimitBlock - if c.DynamicGasLimitBlock != nil { - dynamicGasLimitBlock = c.DynamicGasLimitBlock - } - var banner = "Chain configuration:\n" banner += fmt.Sprintf(" - ChainID: %-8v\n", c.ChainID) banner += fmt.Sprintf(" - Homestead: %-8v\n", c.HomesteadBlock) banner += fmt.Sprintf(" - DAO Fork: %-8v\n", c.DAOForkBlock) banner += fmt.Sprintf(" - DAO Support: %-8v\n", c.DAOForkSupport) + banner += fmt.Sprintf(" - TIP2019: %-8v\n", c.TIP2019Block) banner += fmt.Sprintf(" - Tangerine Whistle (EIP 150): %-8v\n", c.EIP150Block) banner += fmt.Sprintf(" - Spurious Dragon (EIP 155): %-8v\n", c.EIP155Block) banner += fmt.Sprintf(" - Byzantium: %-8v\n", c.ByzantiumBlock) banner += fmt.Sprintf(" - Constantinople: %-8v\n", c.ConstantinopleBlock) banner += fmt.Sprintf(" - Petersburg: %-8v\n", c.PetersburgBlock) banner += fmt.Sprintf(" - Istanbul: %-8v\n", c.IstanbulBlock) - banner += fmt.Sprintf(" - TIP2019Block: %-8v\n", common.TIP2019Block) - banner += fmt.Sprintf(" - TIPSigning: %-8v\n", common.TIPSigning) - banner += fmt.Sprintf(" - TIPRandomize: %-8v\n", common.TIPRandomize) - banner += fmt.Sprintf(" - TIPIncreaseMasternodes: %-8v\n", common.TIPIncreaseMasternodes) - banner += fmt.Sprintf(" - DenylistHFNumber: %-8v\n", common.DenylistHFNumber) - banner += fmt.Sprintf(" - TIPNoHalvingMNReward: %-8v\n", common.TIPNoHalvingMNReward) - banner += fmt.Sprintf(" - TIPXDCX: %-8v\n", common.TIPXDCX) - banner += fmt.Sprintf(" - TIPXDCXLending: %-8v\n", common.TIPXDCXLending) - banner += fmt.Sprintf(" - TIPXDCXCancellationFee: %-8v\n", common.TIPXDCXCancellationFee) - banner += fmt.Sprintf(" - TIPTRC21Fee: %-8v\n", common.TIPTRC21Fee) - banner += fmt.Sprintf(" - Berlin: %-8v\n", berlinBlock) - banner += fmt.Sprintf(" - London: %-8v\n", londonBlock) - banner += fmt.Sprintf(" - Merge: %-8v\n", mergeBlock) - banner += fmt.Sprintf(" - Shanghai: %-8v\n", shanghaiBlock) - banner += fmt.Sprintf(" - BlockNumberGas50x: %-8v\n", common.BlockNumberGas50x) - banner += fmt.Sprintf(" - TIPXDCXMinerDisable: %-8v\n", common.TIPXDCXMinerDisable) - banner += fmt.Sprintf(" - TIPXDCXReceiverDisable: %-8v\n", common.TIPXDCXReceiverDisable) - banner += fmt.Sprintf(" - Eip1559: %-8v\n", eip1559Block) - banner += fmt.Sprintf(" - Cancun: %-8v\n", cancunBlock) - banner += fmt.Sprintf(" - Prague: %-8v\n", pragueBlock) - banner += fmt.Sprintf(" - Osaka: %-8v\n", osakaBlock) - banner += fmt.Sprintf(" - DynamicGasLimitBlock: %-8v\n", dynamicGasLimitBlock) - banner += fmt.Sprintf(" - TIPUpgradeReward: %-8v\n", common.TIPUpgradeReward) - banner += fmt.Sprintf(" - TipUpgradePenalty: %-8v\n", common.TipUpgradePenalty) - banner += fmt.Sprintf(" - TIPEpochHalving: %-8v\n", common.TIPEpochHalving) + banner += fmt.Sprintf(" - TIPSigning: %-8v\n", c.TIPSigningBlock) + banner += fmt.Sprintf(" - TIPRandomize: %-8v\n", c.TIPRandomizeBlock) + banner += fmt.Sprintf(" - TIPIncreaseMasternodes: %-8v\n", c.TIPIncreaseMasternodesBlock) + banner += fmt.Sprintf(" - Denylist: %-8v\n", c.DenylistBlock) + banner += fmt.Sprintf(" - TIPNoHalvingMNReward: %-8v\n", c.TIPNoHalvingMNRewardBlock) + banner += fmt.Sprintf(" - TIPXDCX: %-8v\n", c.TIPXDCXBlock) + banner += fmt.Sprintf(" - TIPXDCXLending: %-8v\n", c.TIPXDCXLendingBlock) + banner += fmt.Sprintf(" - TIPXDCXCancellationFee: %-8v\n", c.TIPXDCXCancellationFeeBlock) + banner += fmt.Sprintf(" - TIPTRC21Fee: %-8v\n", c.TIPTRC21FeeBlock) + banner += fmt.Sprintf(" - Berlin: %-8v\n", c.BerlinBlock) + banner += fmt.Sprintf(" - London: %-8v\n", c.LondonBlock) + banner += fmt.Sprintf(" - Merge: %-8v\n", c.MergeBlock) + banner += fmt.Sprintf(" - Shanghai: %-8v\n", c.ShanghaiBlock) + banner += fmt.Sprintf(" - Gas50x: %-8v\n", c.Gas50xBlock) + banner += fmt.Sprintf(" - TIPXDCXMinerDisable: %-8v\n", c.TIPXDCXMinerDisableBlock) + banner += fmt.Sprintf(" - TIPXDCXReceiverDisable: %-8v\n", c.TIPXDCXReceiverDisableBlock) + banner += fmt.Sprintf(" - Eip1559: %-8v\n", c.Eip1559Block) + banner += fmt.Sprintf(" - Cancun: %-8v\n", c.CancunBlock) + banner += fmt.Sprintf(" - Prague: %-8v\n", c.PragueBlock) + banner += fmt.Sprintf(" - Osaka: %-8v\n", c.OsakaBlock) + banner += fmt.Sprintf(" - DynamicGasLimit: %-8v\n", c.DynamicGasLimitBlock) + banner += fmt.Sprintf(" - TIPUpgradeReward: %-8v\n", c.TIPUpgradeRewardBlock) + banner += fmt.Sprintf(" - TIPUpgradePenalty: %-8v\n", c.TIPUpgradePenaltyBlock) + banner += fmt.Sprintf(" - TIPEpochHalving: %-8v\n", c.TIPEpochHalvingBlock) + banner += fmt.Sprintf(" - TRC21IssuerSMC: %-8s\n", c.TRC21IssuerSMC) + banner += fmt.Sprintf(" - XDCXListingSMC: %-8s\n", c.XDCXListingSMC) + banner += fmt.Sprintf(" - RelayerRegistrationSMC: %-8s\n", c.RelayerRegistrationSMC) + banner += fmt.Sprintf(" - LendingRegistrationSMC: %-8s\n", c.LendingRegistrationSMC) banner += fmt.Sprintf(" - Engine: %v", engine) return banner } @@ -1014,6 +1787,10 @@ func (c *ChainConfig) IsHomestead(num *big.Int) bool { return isForked(c.HomesteadBlock, num) } +func (c *ChainConfig) IsTIP2019(num *big.Int) bool { + return isForked(c.TIP2019Block, num) +} + // IsDAO returns whether num is either equal to the DAO fork block or greater. func (c *ChainConfig) IsDAOFork(num *big.Int) bool { return isForked(c.DAOForkBlock, num) @@ -1039,121 +1816,127 @@ func (c *ChainConfig) IsConstantinople(num *big.Int) bool { return isForked(c.ConstantinopleBlock, num) } -// IsPetersburg returns whether num is either -// - equal to or greater than the PetersburgBlock fork block, -// - OR is nil, and Constantinople is active +// IsPetersburg returns whether num is either equal to the Petersburg fork block or greater. func (c *ChainConfig) IsPetersburg(num *big.Int) bool { - return isForked(common.TIPXDCXCancellationFee, num) || isForked(c.PetersburgBlock, num) + return isForked(c.TIPXDCXCancellationFeeBlock, num) || isForked(c.PetersburgBlock, num) } -// IsIstanbul returns whether num is either equal to the Istanbul fork block or greater. +// IsIstanbul returns whether num is either equal to the TIPXDCXCancellationFeeBlock fork block or greater. func (c *ChainConfig) IsIstanbul(num *big.Int) bool { - return isForked(common.TIPXDCXCancellationFee, num) || isForked(c.IstanbulBlock, num) + return isForked(c.TIPXDCXCancellationFeeBlock, num) || isForked(c.IstanbulBlock, num) +} + +// IsTIPTRC21Fee returns whether num is either equal to the TIPTRC21Fee fork block or greater. +func (c *ChainConfig) IsTIPTRC21Fee(num *big.Int) bool { + return isForked(c.TIPTRC21FeeBlock, num) +} + +func (c *ChainConfig) IsDenylist(num *big.Int) bool { + return isForked(c.DenylistBlock, num) } // IsBerlin returns whether num is either equal to the Berlin fork block or greater. func (c *ChainConfig) IsBerlin(num *big.Int) bool { - return isForked(common.BerlinBlock, num) || isForked(c.BerlinBlock, num) + return isForked(c.BerlinBlock, num) } // IsLondon returns whether num is either equal to the London fork block or greater. func (c *ChainConfig) IsLondon(num *big.Int) bool { - return isForked(common.LondonBlock, num) || isForked(c.LondonBlock, num) + return isForked(c.LondonBlock, num) } // IsMerge returns whether num is either equal to the Merge fork block or greater. // Different from Geth which uses `block.difficulty != nil` func (c *ChainConfig) IsMerge(num *big.Int) bool { - return isForked(common.MergeBlock, num) || isForked(c.MergeBlock, num) + return isForked(c.MergeBlock, num) } // IsShanghai returns whether num is either equal to the Shanghai fork block or greater. func (c *ChainConfig) IsShanghai(num *big.Int) bool { - return isForked(common.ShanghaiBlock, num) || isForked(c.ShanghaiBlock, num) + return isForked(c.ShanghaiBlock, num) +} + +// IsGas50x returns whether num is either equal to the Gas50x fork block or greater. +func (c *ChainConfig) IsGas50x(num *big.Int) bool { + return isForked(c.Gas50xBlock, num) } // IsEIP1559 returns whether num is either equal to the EIP1559 fork block or greater. func (c *ChainConfig) IsEIP1559(num *big.Int) bool { - return isForked(common.Eip1559Block, num) || isForked(c.Eip1559Block, num) + return isForked(c.Eip1559Block, num) } // IsCancun returns whether num is either equal to the Cancun fork block or greater. func (c *ChainConfig) IsCancun(num *big.Int) bool { - return isForked(common.CancunBlock, num) || isForked(c.CancunBlock, num) + return isForked(c.CancunBlock, num) } // IsPrague returns whether num is either equal to the Prague fork block or greater. func (c *ChainConfig) IsPrague(num *big.Int) bool { - return isForked(common.PragueBlock, num) || isForked(c.PragueBlock, num) + return isForked(c.PragueBlock, num) } // IsOsaka returns whether num is either equal to the Osaka fork block or greater. func (c *ChainConfig) IsOsaka(num *big.Int) bool { - return isForked(common.OsakaBlock, num) || isForked(c.OsakaBlock, num) -} - -// IsDynamicGasLimitBlock returns whether num is either equal to the DynamicGasLimitBlock fork block or greater. -func (c *ChainConfig) IsDynamicGasLimitBlock(num *big.Int) bool { - return isForked(common.DynamicGasLimitBlock, num) || isForked(c.DynamicGasLimitBlock, num) + return isForked(c.OsakaBlock, num) } -func (c *ChainConfig) IsTIP2019(num *big.Int) bool { - return isForked(common.TIP2019Block, num) +// IsDynamicGasLimit returns whether num is either equal to the DynamicGasLimitBlock fork block or greater. +func (c *ChainConfig) IsDynamicGasLimit(num *big.Int) bool { + return isForked(c.DynamicGasLimitBlock, num) } func (c *ChainConfig) IsTIPSigning(num *big.Int) bool { - return isForked(common.TIPSigning, num) + return isForked(c.TIPSigningBlock, num) } func (c *ChainConfig) IsTIPRandomize(num *big.Int) bool { - return isForked(common.TIPRandomize, num) + return isForked(c.TIPRandomizeBlock, num) } // IsTIPIncreaseMasternodes using for increase masternodes from 18 to 40 - -// Time update: 23-07-2019 func (c *ChainConfig) IsTIPIncreaseMasternodes(num *big.Int) bool { - return isForked(common.TIPIncreaseMasternodes, num) + return isForked(c.TIPIncreaseMasternodesBlock, num) } func (c *ChainConfig) IsTIPNoHalvingMNReward(num *big.Int) bool { - return isForked(common.TIPNoHalvingMNReward, num) + return isForked(c.TIPNoHalvingMNRewardBlock, num) } func (c *ChainConfig) IsTIPXDCX(num *big.Int) bool { - return isForked(common.TIPXDCX, num) + return isForked(c.TIPXDCXBlock, num) } func (c *ChainConfig) IsTIPXDCXMiner(num *big.Int) bool { - return isForked(common.TIPXDCX, num) && !isForked(common.TIPXDCXMinerDisable, num) + return isForked(c.TIPXDCXBlock, num) && !isForked(c.TIPXDCXMinerDisableBlock, num) } func (c *ChainConfig) IsTIPXDCXReceiver(num *big.Int) bool { - return isForked(common.TIPXDCX, num) && !isForked(common.TIPXDCXReceiverDisable, num) + return isForked(c.TIPXDCXBlock, num) && !isForked(c.TIPXDCXReceiverDisableBlock, num) } func (c *ChainConfig) IsXDCxDisable(num *big.Int) bool { - return isForked(common.TIPXDCXMinerDisable, num) + return isForked(c.TIPXDCXMinerDisableBlock, num) } func (c *ChainConfig) IsTIPXDCXLending(num *big.Int) bool { - return isForked(common.TIPXDCXLending, num) + return isForked(c.TIPXDCXLendingBlock, num) } func (c *ChainConfig) IsTIPXDCXCancellationFee(num *big.Int) bool { - return isForked(common.TIPXDCXCancellationFee, num) + return isForked(c.TIPXDCXCancellationFeeBlock, num) } func (c *ChainConfig) IsTIPUpgradeReward(num *big.Int) bool { - return isForked(common.TIPUpgradeReward, num) + return isForked(c.TIPUpgradeRewardBlock, num) } func (c *ChainConfig) IsTIPUpgradePenalty(num *big.Int) bool { - return isForked(common.TipUpgradePenalty, num) + return isForked(c.TIPUpgradePenaltyBlock, num) } func (c *ChainConfig) IsTIPEpochHalving(num *big.Int) bool { - return isForked(common.TIPEpochHalving, num) + return isForked(c.TIPEpochHalvingBlock, num) } // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). @@ -1195,6 +1978,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) { return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) } + if isForkIncompatible(c.TIP2019Block, newcfg.TIP2019Block, head) { + return newCompatError("TIP2019 fork block", c.TIP2019Block, newcfg.TIP2019Block) + } if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) { return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock) } @@ -1229,15 +2015,54 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.IstanbulBlock, newcfg.IstanbulBlock, head) { return newCompatError("Istanbul fork block", c.IstanbulBlock, newcfg.IstanbulBlock) } + if isForkIncompatible(c.TIPSigningBlock, newcfg.TIPSigningBlock, head) { + return newCompatError("TIPSigning fork block", c.TIPSigningBlock, newcfg.TIPSigningBlock) + } + if isForkIncompatible(c.TIPRandomizeBlock, newcfg.TIPRandomizeBlock, head) { + return newCompatError("TIPRandomize fork block", c.TIPRandomizeBlock, newcfg.TIPRandomizeBlock) + } + if isForkIncompatible(c.TIPIncreaseMasternodesBlock, newcfg.TIPIncreaseMasternodesBlock, head) { + return newCompatError("TIPIncreaseMasternodes fork block", c.TIPIncreaseMasternodesBlock, newcfg.TIPIncreaseMasternodesBlock) + } + if isForkIncompatible(c.DenylistBlock, newcfg.DenylistBlock, head) { + return newCompatError("Denylist fork block", c.DenylistBlock, newcfg.DenylistBlock) + } + if isForkIncompatible(c.TIPNoHalvingMNRewardBlock, newcfg.TIPNoHalvingMNRewardBlock, head) { + return newCompatError("TIPNoHalvingMNReward fork block", c.TIPNoHalvingMNRewardBlock, newcfg.TIPNoHalvingMNRewardBlock) + } + if isForkIncompatible(c.TIPXDCXBlock, newcfg.TIPXDCXBlock, head) { + return newCompatError("TIPXDCX fork block", c.TIPXDCXBlock, newcfg.TIPXDCXBlock) + } + if isForkIncompatible(c.TIPXDCXLendingBlock, newcfg.TIPXDCXLendingBlock, head) { + return newCompatError("TIPXDCXLending fork block", c.TIPXDCXLendingBlock, newcfg.TIPXDCXLendingBlock) + } + if isForkIncompatible(c.TIPXDCXCancellationFeeBlock, newcfg.TIPXDCXCancellationFeeBlock, head) { + return newCompatError("TIPXDCXCancellationFee fork block", c.TIPXDCXCancellationFeeBlock, newcfg.TIPXDCXCancellationFeeBlock) + } + if isForkIncompatible(c.TIPTRC21FeeBlock, newcfg.TIPTRC21FeeBlock, head) { + return newCompatError("TIPTRC21Fee fork block", c.TIPTRC21FeeBlock, newcfg.TIPTRC21FeeBlock) + } if isForkIncompatible(c.BerlinBlock, newcfg.BerlinBlock, head) { return newCompatError("Berlin fork block", c.BerlinBlock, newcfg.BerlinBlock) } if isForkIncompatible(c.LondonBlock, newcfg.LondonBlock, head) { return newCompatError("London fork block", c.LondonBlock, newcfg.LondonBlock) } + if isForkIncompatible(c.MergeBlock, newcfg.MergeBlock, head) { + return newCompatError("Merge fork block", c.MergeBlock, newcfg.MergeBlock) + } if isForkIncompatible(c.ShanghaiBlock, newcfg.ShanghaiBlock, head) { return newCompatError("Shanghai fork block", c.ShanghaiBlock, newcfg.ShanghaiBlock) } + if isForkIncompatible(c.Gas50xBlock, newcfg.Gas50xBlock, head) { + return newCompatError("Gas50x fork block", c.Gas50xBlock, newcfg.Gas50xBlock) + } + if isForkIncompatible(c.TIPXDCXMinerDisableBlock, newcfg.TIPXDCXMinerDisableBlock, head) { + return newCompatError("TIPXDCXMinerDisable fork block", c.TIPXDCXMinerDisableBlock, newcfg.TIPXDCXMinerDisableBlock) + } + if isForkIncompatible(c.TIPXDCXReceiverDisableBlock, newcfg.TIPXDCXReceiverDisableBlock, head) { + return newCompatError("TIPXDCXReceiverDisable fork block", c.TIPXDCXReceiverDisableBlock, newcfg.TIPXDCXReceiverDisableBlock) + } if isForkIncompatible(c.Eip1559Block, newcfg.Eip1559Block, head) { return newCompatError("Eip1559 fork block", c.Eip1559Block, newcfg.Eip1559Block) } @@ -1250,6 +2075,18 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.OsakaBlock, newcfg.OsakaBlock, head) { return newCompatError("Osaka fork block", c.OsakaBlock, newcfg.OsakaBlock) } + if isForkIncompatible(c.DynamicGasLimitBlock, newcfg.DynamicGasLimitBlock, head) { + return newCompatError("DynamicGasLimit fork block", c.DynamicGasLimitBlock, newcfg.DynamicGasLimitBlock) + } + if isForkIncompatible(c.TIPUpgradeRewardBlock, newcfg.TIPUpgradeRewardBlock, head) { + return newCompatError("TIPUpgradeReward fork block", c.TIPUpgradeRewardBlock, newcfg.TIPUpgradeRewardBlock) + } + if isForkIncompatible(c.TIPUpgradePenaltyBlock, newcfg.TIPUpgradePenaltyBlock, head) { + return newCompatError("TIPUpgradePenalty fork block", c.TIPUpgradePenaltyBlock, newcfg.TIPUpgradePenaltyBlock) + } + if isForkIncompatible(c.TIPEpochHalvingBlock, newcfg.TIPEpochHalvingBlock, head) { + return newCompatError("TIPEpochHalving fork block", c.TIPEpochHalvingBlock, newcfg.TIPEpochHalvingBlock) + } if !XDPoSConfigEqual(c.XDPoS, newcfg.XDPoS) { storedblock := big.NewInt(1) if c.XDPoS != nil && c.XDPoS.V2 != nil && c.XDPoS.V2.SwitchBlock != nil { diff --git a/params/config_test.go b/params/config_test.go index 99a653d30710..d1f8ef8e98d0 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -18,8 +18,11 @@ package params import ( "encoding/json" + "errors" + "math" "math/big" "reflect" + "strings" "testing" "github.com/XinFinOrg/XDPoSChain/common" @@ -33,8 +36,18 @@ func TestCheckCompatible(t *testing.T) { wantErr *ConfigCompatError } tests := []test{ - {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, head: 0, wantErr: nil}, - {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, head: 100, wantErr: nil}, + { + stored: AllEthashProtocolChanges, + new: AllEthashProtocolChanges, + head: 0, + wantErr: nil, + }, + { + stored: AllEthashProtocolChanges, + new: AllEthashProtocolChanges, + head: 100, + wantErr: nil, + }, { stored: &ChainConfig{EIP150Block: big.NewInt(10)}, new: &ChainConfig{EIP150Block: big.NewInt(20)}, @@ -63,6 +76,17 @@ func TestCheckCompatible(t *testing.T) { RewindTo: 0, }, }, + { + stored: &ChainConfig{TIP2019Block: big.NewInt(10)}, + new: &ChainConfig{TIP2019Block: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIP2019 fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, { stored: &ChainConfig{HomesteadBlock: big.NewInt(30), EIP150Block: big.NewInt(10)}, new: &ChainConfig{HomesteadBlock: big.NewInt(25), EIP150Block: big.NewInt(20)}, @@ -74,6 +98,248 @@ func TestCheckCompatible(t *testing.T) { RewindTo: 9, }, }, + { + stored: &ChainConfig{TIPSigningBlock: big.NewInt(10)}, + new: &ChainConfig{TIPSigningBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPSigning fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPRandomizeBlock: big.NewInt(10)}, + new: &ChainConfig{TIPRandomizeBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPRandomize fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{DenylistBlock: big.NewInt(10)}, + new: &ChainConfig{DenylistBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "Denylist fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPNoHalvingMNRewardBlock: big.NewInt(10)}, + new: &ChainConfig{TIPNoHalvingMNRewardBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPNoHalvingMNReward fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPXDCXBlock: big.NewInt(10)}, + new: &ChainConfig{TIPXDCXBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPXDCX fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPXDCXLendingBlock: big.NewInt(10)}, + new: &ChainConfig{TIPXDCXLendingBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPXDCXLending fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPXDCXCancellationFeeBlock: big.NewInt(10)}, + new: &ChainConfig{TIPXDCXCancellationFeeBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPXDCXCancellationFee fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPTRC21FeeBlock: big.NewInt(10)}, + new: &ChainConfig{TIPTRC21FeeBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPTRC21Fee fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{BerlinBlock: big.NewInt(10)}, + new: &ChainConfig{BerlinBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "Berlin fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{LondonBlock: big.NewInt(10)}, + new: &ChainConfig{LondonBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "London fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{MergeBlock: big.NewInt(10)}, + new: &ChainConfig{MergeBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "Merge fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{ShanghaiBlock: big.NewInt(10)}, + new: &ChainConfig{ShanghaiBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "Shanghai fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPXDCXMinerDisableBlock: big.NewInt(10)}, + new: &ChainConfig{TIPXDCXMinerDisableBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPXDCXMinerDisable fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPXDCXReceiverDisableBlock: big.NewInt(10)}, + new: &ChainConfig{TIPXDCXReceiverDisableBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPXDCXReceiverDisable fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{Eip1559Block: big.NewInt(10)}, + new: &ChainConfig{Eip1559Block: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "Eip1559 fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{CancunBlock: big.NewInt(10)}, + new: &ChainConfig{CancunBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "Cancun fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{PragueBlock: big.NewInt(10)}, + new: &ChainConfig{PragueBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "Prague fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{OsakaBlock: big.NewInt(10)}, + new: &ChainConfig{OsakaBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "Osaka fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{DynamicGasLimitBlock: big.NewInt(10)}, + new: &ChainConfig{DynamicGasLimitBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "DynamicGasLimit fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPUpgradeRewardBlock: big.NewInt(10)}, + new: &ChainConfig{TIPUpgradeRewardBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPUpgradeReward fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPUpgradePenaltyBlock: big.NewInt(10)}, + new: &ChainConfig{TIPUpgradePenaltyBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPUpgradePenalty fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{TIPEpochHalvingBlock: big.NewInt(10)}, + new: &ChainConfig{TIPEpochHalvingBlock: big.NewInt(20)}, + head: 15, + wantErr: &ConfigCompatError{ + What: "TIPEpochHalving fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, } for _, test := range tests { @@ -84,6 +350,60 @@ func TestCheckCompatible(t *testing.T) { } } +func TestChainConfigValidateForStartup(t *testing.T) { + t.Run("missing field", func(t *testing.T) { + cfg := &ChainConfig{} + err := cfg.CheckConfigForkOrder() + if !errors.Is(err, ErrMissingForkSwitch) { + t.Fatalf("unexpected error: have %v want %v", err, ErrMissingForkSwitch) + } + if err == nil || err.Error() != "invalid chain config: missing fork switch ChainID" { + t.Fatalf("unexpected error string: %v", err) + } + }) + + t.Run("valid config", func(t *testing.T) { + cfg := &ChainConfig{ + ChainID: big.NewInt(1), + TIPTRC21FeeBlock: big.NewInt(0), + } + if err := cfg.CheckConfigForkOrder(); err != nil { + t.Fatalf("ValidateForStartup failed: %v", err) + } + }) +} + +func TestXDPoSMockChainConfigDeclaresModernForks(t *testing.T) { + config := TestXDPoSMockChainConfig + if !assert.NotNil(t, config) { + return + } + assertBlock := func(name string, got *big.Int) { + t.Helper() + if assert.NotNil(t, got, "%s must be explicitly declared on TestXDPoSMockChainConfig", name) { + assert.Zero(t, got.Cmp(common.Big0), "%s must be active from genesis on TestXDPoSMockChainConfig", name) + } + } + + assertBlock("TIP2019Block", config.TIP2019Block) + assertBlock("TIPSigningBlock", config.TIPSigningBlock) + assertBlock("TIPRandomizeBlock", config.TIPRandomizeBlock) + assertBlock("TIPIncreaseMasternodesBlock", config.TIPIncreaseMasternodesBlock) + assertBlock("TIPNoHalvingMNRewardBlock", config.TIPNoHalvingMNRewardBlock) + assertBlock("TIPXDCXBlock", config.TIPXDCXBlock) + assertBlock("TIPXDCXLendingBlock", config.TIPXDCXLendingBlock) + assertBlock("TIPXDCXCancellationFeeBlock", config.TIPXDCXCancellationFeeBlock) + assertBlock("TIPTRC21Fee", config.TIPTRC21FeeBlock) + assertBlock("BerlinBlock", config.BerlinBlock) + assertBlock("LondonBlock", config.LondonBlock) + assertBlock("MergeBlock", config.MergeBlock) + assertBlock("ShanghaiBlock", config.ShanghaiBlock) + assertBlock("Eip1559Block", config.Eip1559Block) + assertBlock("CancunBlock", config.CancunBlock) + assertBlock("PragueBlock", config.PragueBlock) + assertBlock("OsakaBlock", config.OsakaBlock) +} + func TestUpdateV2Config(t *testing.T) { TestXDPoSMockChainConfig.XDPoS.V2.BuildConfigIndex() c := TestXDPoSMockChainConfig.XDPoS.V2.CurrentConfig @@ -134,6 +454,95 @@ func TestBuildConfigIndexDescendingOrder(t *testing.T) { assert.Equal(t, []uint64{15, 10, 5, 2, 0}, v2.ConfigIndex()) } +func TestV2ConfigIndexReturnsCopy(t *testing.T) { + v2 := &V2{ + configIndex: []uint64{3, 2, 1}, + } + + index := v2.ConfigIndex() + index[0] = 99 + + assert.Equal(t, []uint64{3, 2, 1}, v2.ConfigIndex()) +} + +func TestChainConfigCloneDeepCopiesNestedConfig(t *testing.T) { + original := &ChainConfig{ + ChainID: big.NewInt(50), + TIP2019Block: big.NewInt(10), + Gas50xBlock: big.NewInt(15), + TIPXDCXMinerDisableBlock: big.NewInt(20), + TIPXDCXReceiverDisableBlock: big.NewInt(25), + OsakaBlock: big.NewInt(30), + Ethash: new(EthashConfig), + XDPoS: &XDPoSConfig{ + V2: &V2{ + SwitchEpoch: 12, + SwitchBlock: big.NewInt(99), + CurrentConfig: &V2Config{ + SwitchRound: 1, + }, + AllConfigs: map[uint64]*V2Config{ + 1: {SwitchRound: 1}, + }, + }, + }, + } + original.XDPoS.V2.BuildConfigIndex() + + clone := original.Clone() + if assert.NotNil(t, clone) { + assert.NotSame(t, original, clone) + assert.NotSame(t, original.ChainID, clone.ChainID) + assert.NotSame(t, original.TIP2019Block, clone.TIP2019Block) + assert.NotSame(t, original.Gas50xBlock, clone.Gas50xBlock) + assert.NotSame(t, original.TIPXDCXMinerDisableBlock, clone.TIPXDCXMinerDisableBlock) + assert.NotSame(t, original.TIPXDCXReceiverDisableBlock, clone.TIPXDCXReceiverDisableBlock) + assert.NotSame(t, original.OsakaBlock, clone.OsakaBlock) + assert.NotSame(t, original.XDPoS, clone.XDPoS) + assert.NotSame(t, original.XDPoS.V2, clone.XDPoS.V2) + assert.NotSame(t, original.XDPoS.V2.SwitchBlock, clone.XDPoS.V2.SwitchBlock) + assert.NotSame(t, original.XDPoS.V2.CurrentConfig, clone.XDPoS.V2.CurrentConfig) + assert.NotSame(t, original.XDPoS.V2.AllConfigs[1], clone.XDPoS.V2.AllConfigs[1]) + + clone.ChainID.SetInt64(999) + clone.Gas50xBlock.SetInt64(1) + clone.XDPoS.V2.SwitchBlock.SetInt64(123) + clone.XDPoS.V2.CurrentConfig.SwitchRound = 7 + cloneIndex := clone.XDPoS.V2.ConfigIndex() + cloneIndex[0] = 77 + + assert.Equal(t, int64(50), original.ChainID.Int64()) + assert.Equal(t, int64(15), original.Gas50xBlock.Int64()) + assert.Equal(t, int64(99), original.XDPoS.V2.SwitchBlock.Int64()) + assert.Equal(t, uint64(1), original.XDPoS.V2.CurrentConfig.SwitchRound) + assert.Equal(t, []uint64{1}, original.XDPoS.V2.ConfigIndex()) + } +} + +func TestChainConfigGas50xBlockDefaults(t *testing.T) { + tests := []struct { + name string + cfg *ChainConfig + want int64 + }{ + {name: "mainnet", cfg: XDCMainnetChainConfig, want: 80370000}, + {name: "testnet", cfg: TestnetChainConfig, want: 56828700}, + {name: "devnet", cfg: DevnetChainConfig, want: 0}, + {name: "localnet", cfg: LocalnetChainConfig, want: 0}, + {name: "custom default", cfg: &ChainConfig{}, want: 0}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := tc.cfg.Gas50xBlock + if got == nil { + got = big.NewInt(0) + } + assert.Equal(t, tc.want, got.Int64()) + }) + } +} + // Test switch epoch is switchblock divide into epoch per block func TestSwitchEpoch(t *testing.T) { config := XDCMainnetChainConfig.XDPoS @@ -153,6 +562,389 @@ func TestSwitchEpoch(t *testing.T) { assert.Equal(t, config.V2.SwitchEpoch, config.V2.SwitchBlock.Uint64()/epoch) } +func TestBuiltInV2SwitchBlockConstants(t *testing.T) { + assert.Equal(t, MainnetV2SwitchBlock, XDCMainnetChainConfig.XDPoS.V2.SwitchBlock.Uint64()) + assert.Equal(t, XDCMainnetChainConfig.XDPoS.V2.SwitchBlock.Uint64()/XDCMainnetChainConfig.XDPoS.Epoch, XDCMainnetChainConfig.XDPoS.V2.SwitchEpoch) + + assert.Equal(t, TestnetV2SwitchBlock, TestnetChainConfig.XDPoS.V2.SwitchBlock.Uint64()) + assert.Equal(t, TestnetChainConfig.XDPoS.V2.SwitchBlock.Uint64()/TestnetChainConfig.XDPoS.Epoch, TestnetChainConfig.XDPoS.V2.SwitchEpoch) + + assert.Equal(t, DevnetV2SwitchBlock, DevnetChainConfig.XDPoS.V2.SwitchBlock.Uint64()) + assert.Equal(t, DevnetChainConfig.XDPoS.V2.SwitchBlock.Uint64()/DevnetChainConfig.XDPoS.Epoch, DevnetChainConfig.XDPoS.V2.SwitchEpoch) +} + +func TestXDCChainConfigsDeclareForkBlocks(t *testing.T) { + tests := []struct { + name string + config *ChainConfig + tip2019Block *big.Int + tipSigningBlock *big.Int + tipRandomizeBlock *big.Int + tipIncreaseMasternodesBlock *big.Int + denylistBlock *big.Int + tipNoHalvingMNRewardBlock *big.Int + tipXDCXBlock *big.Int + tipXDCXLendingBlock *big.Int + tipXDCXCancellationFeeBlock *big.Int + tipTRC21Fee *big.Int + berlinBlock *big.Int + londonBlock *big.Int + mergeBlock *big.Int + shanghaiBlock *big.Int + tipXDCXMinerDisable *big.Int + tipXDCXReceiverDisable *big.Int + eip1559Block *big.Int + cancunBlock *big.Int + pragueBlock *big.Int + osakaBlock *big.Int + dynamicGasLimitBlock *big.Int + tipUpgradeRewardBlock *big.Int + tipUpgradePenaltyBlock *big.Int + tipEpochHalvingBlock *big.Int + }{ + { + name: "mainnet", + config: XDCMainnetChainConfig, + tip2019Block: big.NewInt(1), + tipSigningBlock: big.NewInt(3000000), + tipRandomizeBlock: big.NewInt(3464000), + tipIncreaseMasternodesBlock: big.NewInt(5000000), + denylistBlock: big.NewInt(38383838), + tipNoHalvingMNRewardBlock: big.NewInt(38383838), + tipXDCXBlock: big.NewInt(38383838), + tipXDCXLendingBlock: big.NewInt(38383838), + tipXDCXCancellationFeeBlock: big.NewInt(38383838), + tipTRC21Fee: big.NewInt(38383838), + berlinBlock: big.NewInt(76321000), + londonBlock: big.NewInt(76321000), + mergeBlock: big.NewInt(76321000), + shanghaiBlock: big.NewInt(76321000), + tipXDCXMinerDisable: big.NewInt(80370000), + tipXDCXReceiverDisable: big.NewInt(80370900), + eip1559Block: big.NewInt(98800200), + cancunBlock: big.NewInt(98802000), + pragueBlock: nil, + osakaBlock: nil, + dynamicGasLimitBlock: nil, + tipUpgradeRewardBlock: nil, + tipUpgradePenaltyBlock: nil, + tipEpochHalvingBlock: nil, + }, + { + name: "testnet", + config: TestnetChainConfig, + tip2019Block: big.NewInt(1), + tipSigningBlock: big.NewInt(3000000), + tipRandomizeBlock: big.NewInt(3464000), + tipIncreaseMasternodesBlock: big.NewInt(5000000), + denylistBlock: big.NewInt(23779191), + tipNoHalvingMNRewardBlock: big.NewInt(23779191), + tipXDCXBlock: big.NewInt(23779191), + tipXDCXLendingBlock: big.NewInt(23779191), + tipXDCXCancellationFeeBlock: big.NewInt(23779191), + tipTRC21Fee: big.NewInt(23779191), + berlinBlock: big.NewInt(61290000), + londonBlock: big.NewInt(61290000), + mergeBlock: big.NewInt(61290000), + shanghaiBlock: big.NewInt(61290000), + tipXDCXMinerDisable: big.NewInt(61290000), + tipXDCXReceiverDisable: big.NewInt(66825000), + eip1559Block: big.NewInt(71550000), + cancunBlock: big.NewInt(71551800), + pragueBlock: nil, + osakaBlock: nil, + dynamicGasLimitBlock: nil, + tipUpgradeRewardBlock: nil, + tipUpgradePenaltyBlock: nil, + tipEpochHalvingBlock: nil, + }, + { + name: "devnet", + config: DevnetChainConfig, + tip2019Block: big.NewInt(0), + tipSigningBlock: big.NewInt(0), + tipRandomizeBlock: big.NewInt(0), + tipIncreaseMasternodesBlock: big.NewInt(0), + denylistBlock: big.NewInt(0), + tipNoHalvingMNRewardBlock: big.NewInt(0), + tipXDCXBlock: big.NewInt(0), + tipXDCXLendingBlock: big.NewInt(0), + tipXDCXCancellationFeeBlock: big.NewInt(0), + tipTRC21Fee: big.NewInt(0), + berlinBlock: big.NewInt(0), + londonBlock: big.NewInt(0), + mergeBlock: big.NewInt(0), + shanghaiBlock: big.NewInt(0), + tipXDCXMinerDisable: big.NewInt(0), + tipXDCXReceiverDisable: big.NewInt(0), + eip1559Block: big.NewInt(250000), + cancunBlock: big.NewInt(250000), + pragueBlock: big.NewInt(5000000), + osakaBlock: nil, + dynamicGasLimitBlock: big.NewInt(5000000), + tipUpgradeRewardBlock: big.NewInt(5000000), + tipUpgradePenaltyBlock: big.NewInt(5000000), + tipEpochHalvingBlock: nil, + }, + { + name: "localnet", + config: LocalnetChainConfig, + tip2019Block: big.NewInt(0), + tipSigningBlock: big.NewInt(0), + tipRandomizeBlock: big.NewInt(0), + tipIncreaseMasternodesBlock: big.NewInt(0), + denylistBlock: big.NewInt(0), + tipNoHalvingMNRewardBlock: big.NewInt(0), + tipXDCXBlock: big.NewInt(0), + tipXDCXLendingBlock: big.NewInt(0), + tipXDCXCancellationFeeBlock: big.NewInt(0), + tipTRC21Fee: big.NewInt(0), + berlinBlock: big.NewInt(0), + londonBlock: big.NewInt(0), + mergeBlock: big.NewInt(0), + shanghaiBlock: big.NewInt(0), + tipXDCXMinerDisable: big.NewInt(0), + tipXDCXReceiverDisable: big.NewInt(0), + eip1559Block: big.NewInt(0), + cancunBlock: big.NewInt(0), + pragueBlock: nil, + osakaBlock: nil, + dynamicGasLimitBlock: nil, + tipUpgradeRewardBlock: nil, + tipUpgradePenaltyBlock: nil, + tipEpochHalvingBlock: nil, + }, + } + + assertBlock := func(t *testing.T, fork string, got, want *big.Int) { + t.Helper() + if want == nil { + assert.Nil(t, got, "%s block must be nil when unscheduled", fork) + return + } + if assert.NotNil(t, got, "%s block must be declared", fork) { + assert.Equal(t, 0, got.Cmp(want), "%s block mismatch", fork) + } + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if !assert.NotNil(t, test.config, "chain config must not be nil") { + return + } + assertBlock(t, "TIP2019", test.config.TIP2019Block, test.tip2019Block) + assertBlock(t, "TIPSigning", test.config.TIPSigningBlock, test.tipSigningBlock) + assertBlock(t, "TIPRandomize", test.config.TIPRandomizeBlock, test.tipRandomizeBlock) + assertBlock(t, "TIPIncreaseMasternodes", test.config.TIPIncreaseMasternodesBlock, test.tipIncreaseMasternodesBlock) + assertBlock(t, "DenylistHardFork", test.config.DenylistBlock, test.denylistBlock) + assertBlock(t, "TIPNoHalvingMNReward", test.config.TIPNoHalvingMNRewardBlock, test.tipNoHalvingMNRewardBlock) + assertBlock(t, "TIPXDCX", test.config.TIPXDCXBlock, test.tipXDCXBlock) + assertBlock(t, "TIPXDCXLending", test.config.TIPXDCXLendingBlock, test.tipXDCXLendingBlock) + assertBlock(t, "TIPXDCXCancellationFee", test.config.TIPXDCXCancellationFeeBlock, test.tipXDCXCancellationFeeBlock) + assertBlock(t, "TIPTRC21Fee", test.config.TIPTRC21FeeBlock, test.tipTRC21Fee) + assertBlock(t, "Berlin", test.config.BerlinBlock, test.berlinBlock) + assertBlock(t, "London", test.config.LondonBlock, test.londonBlock) + assertBlock(t, "Merge", test.config.MergeBlock, test.mergeBlock) + assertBlock(t, "Shanghai", test.config.ShanghaiBlock, test.shanghaiBlock) + assertBlock(t, "TIPXDCXMinerDisable", test.config.TIPXDCXMinerDisableBlock, test.tipXDCXMinerDisable) + assertBlock(t, "TIPXDCXReceiverDisable", test.config.TIPXDCXReceiverDisableBlock, test.tipXDCXReceiverDisable) + assertBlock(t, "Eip1559", test.config.Eip1559Block, test.eip1559Block) + assertBlock(t, "Cancun", test.config.CancunBlock, test.cancunBlock) + assertBlock(t, "Prague", test.config.PragueBlock, test.pragueBlock) + assertBlock(t, "Osaka", test.config.OsakaBlock, test.osakaBlock) + assertBlock(t, "DynamicGasLimit", test.config.DynamicGasLimitBlock, test.dynamicGasLimitBlock) + assertBlock(t, "TIPUpgradeReward", test.config.TIPUpgradeRewardBlock, test.tipUpgradeRewardBlock) + assertBlock(t, "TIPUpgradePenalty", test.config.TIPUpgradePenaltyBlock, test.tipUpgradePenaltyBlock) + assertBlock(t, "TIPEpochHalving", test.config.TIPEpochHalvingBlock, test.tipEpochHalvingBlock) + }) + } +} + +func TestForkActivationIgnoresCommonFallbacks(t *testing.T) { + const zeroAddress0x = "0x0000000000000000000000000000000000000000" + config := &ChainConfig{} + block := big.NewInt(1) + + assert.False(t, config.IsTIP2019(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPSigning(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPRandomize(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPIncreaseMasternodes(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsDenylist(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPNoHalvingMNReward(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPXDCX(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPXDCXLending(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPXDCXCancellationFee(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsBerlin(block)) + assert.False(t, config.IsLondon(block)) + assert.False(t, config.IsMerge(block)) + assert.False(t, config.IsShanghai(block)) + assert.False(t, config.IsTIPXDCXMiner(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPXDCXReceiver(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsXDCxDisable(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsCancun(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsPrague(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsOsaka(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsDynamicGasLimit(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPUpgradeReward(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPUpgradePenalty(big.NewInt(math.MaxInt64))) + assert.False(t, config.IsTIPEpochHalving(big.NewInt(math.MaxInt64))) + + description := config.Description() + assertDescriptionLineValue := func(t *testing.T, label, value string) { + t.Helper() + for _, line := range strings.Split(description, "\n") { + if strings.Contains(line, label) { + assert.Contains(t, line, value, "description line for %s should contain %s", label, value) + return + } + } + assert.Failf(t, "missing description line", "description must contain a line for %s", label) + } + + assertDescriptionLineValue(t, "TIP2019:", "") + assertDescriptionLineValue(t, "TIPSigning:", "") + assertDescriptionLineValue(t, "TIPRandomize:", "") + assertDescriptionLineValue(t, "TIPIncreaseMasternodes:", "") + assertDescriptionLineValue(t, "Denylist:", "") + assertDescriptionLineValue(t, "TIPNoHalvingMNReward:", "") + assertDescriptionLineValue(t, "TIPXDCX:", "") + assertDescriptionLineValue(t, "TIPXDCXLending:", "") + assertDescriptionLineValue(t, "TIPXDCXCancellationFee:", "") + assertDescriptionLineValue(t, "TIPTRC21Fee:", "") + assertDescriptionLineValue(t, "Berlin:", "") + assertDescriptionLineValue(t, "London:", "") + assertDescriptionLineValue(t, "Merge:", "") + assertDescriptionLineValue(t, "Shanghai:", "") + assertDescriptionLineValue(t, "TIPXDCXMinerDisable:", "") + assertDescriptionLineValue(t, "TIPXDCXReceiverDisable:", "") + assertDescriptionLineValue(t, "Cancun:", "") + assertDescriptionLineValue(t, "Prague:", "") + assertDescriptionLineValue(t, "Osaka:", "") + assertDescriptionLineValue(t, "DynamicGasLimit:", "") + assertDescriptionLineValue(t, "TIPUpgradeReward:", "") + assertDescriptionLineValue(t, "TIPUpgradePenalty:", "") + assertDescriptionLineValue(t, "TIPEpochHalving:", "") + assertDescriptionLineValue(t, "TRC21IssuerSMC:", zeroAddress0x) + assertDescriptionLineValue(t, "XDCXListingSMC:", zeroAddress0x) + assertDescriptionLineValue(t, "RelayerRegistrationSMC:", zeroAddress0x) + assertDescriptionLineValue(t, "LendingRegistrationSMC:", zeroAddress0x) +} + +func TestChainConfigStringIncludesAllFields(t *testing.T) { + config := &ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(2), + DAOForkBlock: big.NewInt(3), + DAOForkSupport: true, + EIP150Block: big.NewInt(4), + EIP155Block: big.NewInt(5), + EIP158Block: big.NewInt(6), + ByzantiumBlock: big.NewInt(7), + ConstantinopleBlock: big.NewInt(8), + PetersburgBlock: big.NewInt(9), + IstanbulBlock: big.NewInt(10), + BerlinBlock: big.NewInt(11), + LondonBlock: big.NewInt(12), + MergeBlock: big.NewInt(13), + ShanghaiBlock: big.NewInt(14), + Eip1559Block: big.NewInt(15), + CancunBlock: big.NewInt(16), + PragueBlock: big.NewInt(17), + OsakaBlock: big.NewInt(18), + TIP2019Block: big.NewInt(19), + TIPSigningBlock: big.NewInt(20), + TIPRandomizeBlock: big.NewInt(21), + TIPIncreaseMasternodesBlock: big.NewInt(22), + DenylistBlock: big.NewInt(23), + TIPNoHalvingMNRewardBlock: big.NewInt(24), + TIPXDCXBlock: big.NewInt(25), + TIPXDCXLendingBlock: big.NewInt(26), + TIPXDCXCancellationFeeBlock: big.NewInt(27), + TIPTRC21FeeBlock: big.NewInt(28), + TIPXDCXMinerDisableBlock: big.NewInt(29), + TIPXDCXReceiverDisableBlock: big.NewInt(30), + DynamicGasLimitBlock: big.NewInt(31), + TIPUpgradeRewardBlock: big.NewInt(32), + TIPUpgradePenaltyBlock: big.NewInt(33), + TIPEpochHalvingBlock: big.NewInt(34), + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Ethash: new(EthashConfig), + Clique: &CliqueConfig{Period: 1, Epoch: 2}, + XDPoS: &XDPoSConfig{ + Period: 2, + Epoch: 900, + Reward: 5000, + RewardCheckpoint: 900, + Gap: 450, + FoundationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"), + V2: &V2{ + SwitchEpoch: 1, + SwitchBlock: big.NewInt(900), + CurrentConfig: &V2Config{ + MaxMasternodes: 18, + }, + }, + }, + } + + got := config.String() + assert.NotContains(t, got, "SchemaVersion:") + + encoded, err := json.Marshal(config) + assert.NoError(t, err) + assert.NotContains(t, string(encoded), "schemaVersion") + + for _, label := range []string{ + "ChainID:", + "Homestead:", + "DAOFork:", + "DAOForkSupport:", + "TIP2019:", + "EIP150:", + "EIP155:", + "EIP158:", + "Byzantium:", + "Constantinople:", + "Petersburg:", + "Istanbul:", + "TIPSigning:", + "TIPRandomize:", + "TIPIncreaseMasternodes:", + "Denylist:", + "TIPNoHalvingMNReward:", + "TIPXDCX:", + "TIPXDCXLending:", + "TIPXDCXCancellationFee:", + "TIPTRC21Fee:", + "Berlin:", + "London:", + "Merge:", + "Shanghai:", + "TIPXDCXMinerDisable:", + "TIPXDCXReceiverDisable:", + "Eip1559:", + "Cancun:", + "Prague:", + "Osaka:", + "DynamicGasLimit:", + "TIPUpgradeReward:", + "TIPUpgradePenalty:", + "TIPEpochHalving:", + "TRC21IssuerSMC:", + "XDCXListingSMC:", + "RelayerRegistrationSMC:", + "LendingRegistrationSMC:", + "Ethash:", + "Clique:", + "XDPoS:", + } { + assert.Contains(t, got, label) + } +} + func TestXDPoSConfigUnmarshalLegacyFoundationWalletAddr(t *testing.T) { const raw = `{"period":2,"epoch":900,"reward":5000,"rewardCheckpoint":900,"gap":450,"foudationWalletAddr":"xdc746249c61f5832c5eed53172776b460491bdcd5c"}` @@ -170,3 +962,23 @@ func TestXDPoSConfigUnmarshalFoundationWalletAddrPrecedence(t *testing.T) { assert.NoError(t, err) assert.Equal(t, common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"), cfg.FoundationWalletAddr) } + +func TestGetBuiltInChainConfigByHashHashOnly(t *testing.T) { + tests := []struct { + name string + hash common.Hash + want bool + }{ + {name: "mainnet hash", hash: MainnetGenesisHash, want: true}, + {name: "testnet hash", hash: TestnetGenesisHash, want: true}, + {name: "devnet hash", hash: DevnetGenesisHash, want: true}, + {name: "empty hash", hash: common.Hash{}, want: false}, + {name: "random hash", hash: common.HexToHash("0x1"), want: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, GetBuiltInChainConfigByHash(tt.hash) != nil) + }) + } +} diff --git a/tests/transaction_test.go b/tests/transaction_test.go index 494181c0ddf2..98892ec19c8f 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -28,21 +28,24 @@ func TestTransaction(t *testing.T) { txt := new(testMatcher) txt.config(`^Homestead/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), + HomesteadBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), }) txt.config(`^EIP155/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ChainID: big.NewInt(1), + TIPTRC21FeeBlock: big.NewInt(0), }) txt.config(`^Byzantium/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + TIPTRC21FeeBlock: big.NewInt(0), }) txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) { diff --git a/tests/vm_test.go b/tests/vm_test.go index 1816d02d6022..6c2eadd484db 100644 --- a/tests/vm_test.go +++ b/tests/vm_test.go @@ -20,16 +20,13 @@ import ( "math/big" "testing" - "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/core/vm" + "github.com/XinFinOrg/XDPoSChain/params" ) func TestVM(t *testing.T) { - oldTIPXDCXCancellationFee := new(big.Int).Set(common.TIPXDCXCancellationFee) - defer func() { - common.TIPXDCXCancellationFee = oldTIPXDCXCancellationFee - }() - common.TIPXDCXCancellationFee = big.NewInt(100000000) + chainConfig := *params.MainnetChainConfig + chainConfig.TIPXDCXCancellationFeeBlock = big.NewInt(100000000) vmt := new(testMatcher) vmt.fails("^vmSystemOperationsTest.json/createNameRegistrator$", "fails without parallel execution") @@ -39,6 +36,7 @@ func TestVM(t *testing.T) { vmt.skipShortMode("^vmInputLimits(Light)?.json") vmt.walk(t, vmTestDir, func(t *testing.T, name string, test *VMTest) { + test.chainConfig = &chainConfig withTrace(t, test.json.Exec.GasLimit, func(vmconfig vm.Config) error { return vmt.checkFailure(t, name, test.Run(vmconfig)) }) diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index 505f49c21dc6..1986fd134d64 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -39,7 +39,8 @@ import ( // VMTest checks EVM execution without block or transaction context. // See https://github.com/ethereum/tests/wiki/VM-Tests for the test format specification. type VMTest struct { - json vmJSON + json vmJSON + chainConfig *params.ChainConfig } func (t *VMTest) UnmarshalJSON(data []byte) error { @@ -148,7 +149,11 @@ func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM { GasLimit: t.json.Env.GasLimit, Difficulty: t.json.Env.Difficulty, } - evm := vm.NewEVM(context, statedb, nil, params.MainnetChainConfig, vmconfig) + chainConfig := t.chainConfig + if chainConfig == nil { + chainConfig = params.MainnetChainConfig + } + evm := vm.NewEVM(context, statedb, nil, chainConfig, vmconfig) evm.SetTxContext(txContext) return evm }