From 93fd844b1e85366ee9c1c4a3fb9e9399220534cc Mon Sep 17 00:00:00 2001 From: mboben Date: Tue, 12 Mar 2024 14:55:51 +0100 Subject: [PATCH] Prioritised submitter contract (#26) * Added prioritised handling of submitter contract * Fork times for submitter contract * Simplified function for checking ftso prioritised contract * Change of default attestors addresses * Updated submitter fork addresses * Updated submitter fork test date * Fixed failing test * Updated patch version * Changed submitter fork time for coston 2 --------- Co-authored-by: Marko Boben --- avalanchego/version/constants.go | 2 +- coreth/core/daemon.go | 53 ++++++++++++++++++++++++++++++-- coreth/core/daemon_test.go | 30 ++++++++++++++++++ coreth/core/state_connector.go | 34 ++++++++++++++------ coreth/core/state_transition.go | 24 ++++++++------- 5 files changed, 119 insertions(+), 24 deletions(-) diff --git a/avalanchego/version/constants.go b/avalanchego/version/constants.go index ab2809fd..57654a75 100644 --- a/avalanchego/version/constants.go +++ b/avalanchego/version/constants.go @@ -14,7 +14,7 @@ var ( Current = &Semantic{ Major: 1, Minor: 7, - Patch: 1806, + Patch: 1807, } CurrentApp = &Application{ Major: Current.Major, diff --git a/coreth/core/daemon.go b/coreth/core/daemon.go index 90bd8cc7..acf55eb3 100644 --- a/coreth/core/daemon.go +++ b/coreth/core/daemon.go @@ -6,11 +6,26 @@ package core import ( "fmt" "math/big" + "os" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ava-labs/coreth/core/vm" + "github.com/ava-labs/coreth/params" +) + +var ( + // Define activation times for submitter contract + submitterContractActivationTimeFlare = big.NewInt(time.Date(2024, time.March, 26, 12, 0, 0, 0, time.UTC).Unix()) + submitterContractActivationTimeCostwo = big.NewInt(time.Date(2024, time.March, 7, 12, 0, 0, 0, time.UTC).Unix()) + + // Define ftso and submitter contract addresses + prioritisedFTSOContractAddress = common.HexToAddress("0x1000000000000000000000000000000000000003") + + prioritisedSubmitterContractAddress = common.HexToAddress("0x2cA6571Daa15ce734Bbd0Bf27D5C9D16787fc33f") + prioritisedSubmitterContractAddressEnv = common.HexToAddress(os.Getenv("SUBMITTER_CONTRACT_ADDRESS")) // for local and staging chains ) // Define errors @@ -73,10 +88,35 @@ func GetDaemonSelector(blockTime *big.Int) []byte { } } -func GetPrioritisedFTSOContract(blockTime *big.Int) string { +func isPrioritisedFTSOContract(to *common.Address) bool { + return to != nil && *to == prioritisedFTSOContractAddress +} + +func isPrioritisedSubmitterContract(chainID *big.Int, to *common.Address, blockTime *big.Int) bool { switch { + case to == nil || chainID == nil || blockTime == nil: + return false + case chainID.Cmp(params.FlareChainID) == 0: + return *to == prioritisedSubmitterContractAddress && + blockTime.Cmp(submitterContractActivationTimeFlare) > 0 + case chainID.Cmp(params.CostwoChainID) == 0: + return *to == prioritisedSubmitterContractAddress && + blockTime.Cmp(submitterContractActivationTimeCostwo) > 0 + case chainID.Cmp(params.LocalFlareChainID) == 0 || chainID.Cmp(params.StagingChainID) == 0: + return *to == prioritisedSubmitterContractAddressEnv default: - return "0x1000000000000000000000000000000000000003" + return false + } +} + +func IsPrioritisedContractCall(chainID *big.Int, to *common.Address, ret []byte, blockTime *big.Int) bool { + switch { + case isPrioritisedFTSOContract(to): + return true + case isPrioritisedSubmitterContract(chainID, to, blockTime): + return !isZeroSlice(ret) + default: + return false } } @@ -157,3 +197,12 @@ func atomicDaemonAndMint(evm EVMCaller, log log.Logger) { log.Warn("Daemon error", "error", daemonErr) } } + +func isZeroSlice(s []byte) bool { + for i := len(s) - 1; i >= 0; i-- { + if s[i] != 0 { + return false + } + } + return true +} diff --git a/coreth/core/daemon_test.go b/coreth/core/daemon_test.go index 88d224da..7be96a2f 100644 --- a/coreth/core/daemon_test.go +++ b/coreth/core/daemon_test.go @@ -7,11 +7,13 @@ import ( "errors" "math/big" "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ava-labs/coreth/core/vm" + "github.com/ava-labs/coreth/params" ) // Define a mock structure to spy and mock values for daemon calls @@ -476,3 +478,31 @@ func TestDaemonShouldNotMintMoreThanLimit(t *testing.T) { t.Errorf("Add balance call count not as expected. got %d want 1", defaultEVMMock.mockEVMCallerData.addBalanceCalls) } } + +func TestPrioritisedContract(t *testing.T) { + address := common.HexToAddress("0x123456789aBCdEF123456789aBCdef123456789A") + preForkTime := big.NewInt(time.Date(2024, time.March, 20, 12, 0, 0, 0, time.UTC).Unix()) + postForkTime := big.NewInt(time.Date(2024, time.March, 27, 12, 0, 0, 0, time.UTC).Unix()) + ret0 := [32]byte{} + ret1 := [32]byte{} + ret1[31] = 1 + + if IsPrioritisedContractCall(params.FlareChainID, &address, nil, preForkTime) { + t.Errorf("Expected false for wrong address") + } + if !IsPrioritisedContractCall(params.FlareChainID, &prioritisedFTSOContractAddress, nil, preForkTime) { + t.Errorf("Expected true for FTSO contract") + } + if IsPrioritisedContractCall(params.FlareChainID, &prioritisedSubmitterContractAddress, ret1[:], preForkTime) { + t.Errorf("Expected false for submitter contract before activation") + } + if !IsPrioritisedContractCall(params.FlareChainID, &prioritisedSubmitterContractAddress, ret1[:], postForkTime) { + t.Errorf("Expected true for submitter contract after activation") + } + if IsPrioritisedContractCall(params.FlareChainID, &prioritisedSubmitterContractAddress, ret0[:], postForkTime) { + t.Errorf("Expected false for submitter contract with wrong return value") + } + if IsPrioritisedContractCall(params.FlareChainID, &prioritisedSubmitterContractAddress, nil, postForkTime) { + t.Errorf("Expected false for submitter contract with no return value") + } +} diff --git a/coreth/core/state_connector.go b/coreth/core/state_connector.go index 06993612..2792735b 100644 --- a/coreth/core/state_connector.go +++ b/coreth/core/state_connector.go @@ -115,16 +115,30 @@ func FinaliseRoundSelector(chainID *big.Int, blockTime *big.Int) []byte { func GetDefaultAttestors(chainID *big.Int, blockTime *big.Int) []common.Address { switch { case chainID.Cmp(params.FlareChainID) == 0: - return []common.Address{ - common.HexToAddress("0x0988Cf4828F4e4eD0cE7c07467E70e19095Ee152"), - common.HexToAddress("0x6BC7DCa62010D418eB72CCdc58561e00C5868Ef1"), - common.HexToAddress("0xE34Bb361536610a9DCcEa5292262e36AfF65c06c"), - common.HexToAddress("0x8A3D627D86A81F5D21683F4963565C63DB5e1309"), - common.HexToAddress("0x2D3e7e4b19bDc920fd9C57BD3072A31F5a59FeC8"), - common.HexToAddress("0x6455dC38fdF739b6fE021b30C7D9672C1c6DEb5c"), - common.HexToAddress("0x49893c5Dfc035F4eE4E46faC014f6D4bC80F7f92"), - common.HexToAddress("0x08e8b2Af4874e920de27723576A13d66008Af523"), - common.HexToAddress("0x5D2f75392DdDa69a2818021dd6a64937904c8352"), + if blockTime.Cmp(submitterContractActivationTimeFlare) > 0 { + return []common.Address{ + common.HexToAddress("0x4E07E1F3DB3Dc9BAd56Cc829747cc0148234329F"), + common.HexToAddress("0xB264Fad6Fdc65767998f93501945aB8F9108809d"), + common.HexToAddress("0x366BeC54195bfD45DBB34b79Ad2dEC4010598947"), + common.HexToAddress("0x2665B179d5fCE1118f06e23B5d6E7617c5Ff733A"), + common.HexToAddress("0x65cBaFaDD7C914179aabcE9C35f918a4E36AfFf9"), + common.HexToAddress("0x7eC6a7C7c4Ef003A75DC6c06352B48B37Ac2191B"), + common.HexToAddress("0xEa9bC2F98eFFC6A27E2C31733c1905961826f73B"), + common.HexToAddress("0xA4aA75a9B49c7f2B4be62b2999d7103E78D004C7"), + common.HexToAddress("0x4DF8436D7578C2d3bc73d33B6644913e131B70FC"), + } + } else { + return []common.Address{ + common.HexToAddress("0x0988Cf4828F4e4eD0cE7c07467E70e19095Ee152"), + common.HexToAddress("0x6BC7DCa62010D418eB72CCdc58561e00C5868Ef1"), + common.HexToAddress("0xE34Bb361536610a9DCcEa5292262e36AfF65c06c"), + common.HexToAddress("0x8A3D627D86A81F5D21683F4963565C63DB5e1309"), + common.HexToAddress("0x2D3e7e4b19bDc920fd9C57BD3072A31F5a59FeC8"), + common.HexToAddress("0x6455dC38fdF739b6fE021b30C7D9672C1c6DEb5c"), + common.HexToAddress("0x49893c5Dfc035F4eE4E46faC014f6D4bC80F7f92"), + common.HexToAddress("0x08e8b2Af4874e920de27723576A13d66008Af523"), + common.HexToAddress("0x5D2f75392DdDa69a2818021dd6a64937904c8352"), + } } case chainID.Cmp(params.SongbirdChainID) == 0: return []common.Address{ diff --git a/coreth/core/state_transition.go b/coreth/core/state_transition.go index d6a49bb2..77d815d3 100644 --- a/coreth/core/state_transition.go +++ b/coreth/core/state_transition.go @@ -56,8 +56,10 @@ The state transitioning model does all the necessary work to work out a valid ne 3) Create a new state object if the recipient is \0*32 4) Value transfer == If contract creation == - 4a) Attempt to run transaction data - 4b) If valid, use result as code for the new state object + + 4a) Attempt to run transaction data + 4b) If valid, use result as code for the new state object + == end == 5) Run Script section 6) Derive new state root @@ -300,13 +302,13 @@ func (st *StateTransition) preCheck() error { // TransitionDb will transition the state by applying the current message and // returning the evm execution result with following fields. // -// - used gas: -// total gas used (including gas being refunded) -// - returndata: -// the returned data from evm -// - concrete execution error: -// various **EVM** error which aborts the execution, -// e.g. ErrOutOfGas, ErrExecutionReverted +// - used gas: +// total gas used (including gas being refunded) +// - returndata: +// the returned data from evm +// - concrete execution error: +// various **EVM** error which aborts the execution, +// e.g. ErrOutOfGas, ErrExecutionReverted // // However if any consensus issue encountered, return the error directly with // nil evm execution result. @@ -417,8 +419,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } st.refundGas(rules.IsApricotPhase1) - if vmerr == nil && msg.To() != nil && *msg.To() == common.HexToAddress(GetPrioritisedFTSOContract(timestamp)) && st.initialGas <= GetMaxFTSOGasLimit(timestamp) { - nominalGasUsed := uint64(params.TxGas) // 21000 + if vmerr == nil && IsPrioritisedContractCall(chainID, msg.To(), ret, timestamp) && st.initialGas <= GetMaxFTSOGasLimit(timestamp) { + nominalGasUsed := params.TxGas // 21000 nominalGasPrice := uint64(params.ApricotPhase4MinBaseFee) // 25_000_000_000; the max base fee is 1_000_000_000_000 nominalFee := new(big.Int).Mul(new(big.Int).SetUint64(nominalGasUsed), new(big.Int).SetUint64(nominalGasPrice)) actualGasUsed := st.gasUsed()