github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/u2u/contracts/evmwriter/evm_writer.go (about) 1 package evmwriter 2 3 import ( 4 "bytes" 5 "math/big" 6 "strings" 7 8 "github.com/unicornultrafoundation/go-u2u/accounts/abi" 9 "github.com/unicornultrafoundation/go-u2u/common" 10 "github.com/unicornultrafoundation/go-u2u/core/vm" 11 "github.com/unicornultrafoundation/go-u2u/params" 12 13 "github.com/unicornultrafoundation/go-u2u/u2u/contracts/driver" 14 ) 15 16 var ( 17 // ContractAddress is the EvmWriter pre-compiled contract address 18 ContractAddress = common.HexToAddress("0xd100ec0000000000000000000000000000000000") 19 // ContractABI is the input ABI used to generate the binding from 20 ContractABI string = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"AdvanceEpochs\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"diff\",\"type\":\"bytes\"}],\"name\":\"UpdateNetworkRules\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"}],\"name\":\"UpdateNetworkVersion\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"}],\"name\":\"UpdateValidatorPubkey\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"}],\"name\":\"UpdateValidatorWeight\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"backend\",\"type\":\"address\"}],\"name\":\"UpdatedBackend\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_backend\",\"type\":\"address\"}],\"name\":\"setBackend\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_backend\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_evmWriterAddress\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"acc\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setBalance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"acc\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"}],\"name\":\"copyCode\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"acc\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"with\",\"type\":\"address\"}],\"name\":\"swapCode\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"acc\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"value\",\"type\":\"bytes32\"}],\"name\":\"setStorage\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"acc\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"diff\",\"type\":\"uint256\"}],\"name\":\"incNonce\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"diff\",\"type\":\"bytes\"}],\"name\":\"updateNetworkRules\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"}],\"name\":\"updateNetworkVersion\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"advanceEpochs\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"validatorID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateValidatorWeight\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"validatorID\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"}],\"name\":\"updateValidatorPubkey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_auth\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"validatorID\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deactivatedEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deactivatedTime\",\"type\":\"uint256\"}],\"name\":\"setGenesisValidator\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"toValidatorID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lockedStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lockupFromEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lockupEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lockupDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"earlyUnlockPenalty\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewards\",\"type\":\"uint256\"}],\"name\":\"setGenesisDelegation\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"validatorID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"}],\"name\":\"deactivateValidator\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"nextValidatorIDs\",\"type\":\"uint256[]\"}],\"name\":\"sealEpochValidators\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"offlineTimes\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"offlineBlocks\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"uptimes\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"originatedTxsFee\",\"type\":\"uint256[]\"}],\"name\":\"sealEpoch\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"offlineTimes\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"offlineBlocks\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"uptimes\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"originatedTxsFee\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"usedGas\",\"type\":\"uint256\"}],\"name\":\"sealEpochV1\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" 21 ) 22 23 var ( 24 setBalanceMethodID []byte 25 copyCodeMethodID []byte 26 swapCodeMethodID []byte 27 setStorageMethodID []byte 28 incNonceMethodID []byte 29 ) 30 31 func init() { 32 abi, err := abi.JSON(strings.NewReader(ContractABI)) 33 if err != nil { 34 panic(err) 35 } 36 37 for name, constID := range map[string]*[]byte{ 38 "setBalance": &setBalanceMethodID, 39 "copyCode": ©CodeMethodID, 40 "swapCode": &swapCodeMethodID, 41 "setStorage": &setStorageMethodID, 42 "incNonce": &incNonceMethodID, 43 } { 44 method, exist := abi.Methods[name] 45 if !exist { 46 panic("unknown EvmWriter method") 47 } 48 49 *constID = make([]byte, len(method.ID)) 50 copy(*constID, method.ID) 51 } 52 } 53 54 type PreCompiledContract struct{} 55 56 func (_ PreCompiledContract) Run(stateDB vm.StateDB, _ vm.BlockContext, txCtx vm.TxContext, caller common.Address, input []byte, suppliedGas uint64) ([]byte, uint64, error) { 57 if caller != driver.ContractAddress { 58 return nil, 0, vm.ErrExecutionReverted 59 } 60 if len(input) < 4 { 61 return nil, 0, vm.ErrExecutionReverted 62 } 63 if bytes.Equal(input[:4], setBalanceMethodID) { 64 input = input[4:] 65 // setBalance 66 if suppliedGas < params.CallValueTransferGas { 67 return nil, 0, vm.ErrOutOfGas 68 } 69 suppliedGas -= params.CallValueTransferGas 70 if len(input) != 64 { 71 return nil, 0, vm.ErrExecutionReverted 72 } 73 74 acc := common.BytesToAddress(input[12:32]) 75 input = input[32:] 76 value := new(big.Int).SetBytes(input[:32]) 77 78 if acc == txCtx.Origin { 79 // Origin balance shouldn't decrease during his transaction 80 return nil, 0, vm.ErrExecutionReverted 81 } 82 83 balance := stateDB.GetBalance(acc) 84 if balance.Cmp(value) >= 0 { 85 diff := new(big.Int).Sub(balance, value) 86 stateDB.SubBalance(acc, diff) 87 } else { 88 diff := new(big.Int).Sub(value, balance) 89 stateDB.AddBalance(acc, diff) 90 } 91 } else if bytes.Equal(input[:4], copyCodeMethodID) { 92 input = input[4:] 93 // copyCode 94 if suppliedGas < params.CreateGas { 95 return nil, 0, vm.ErrOutOfGas 96 } 97 suppliedGas -= params.CreateGas 98 if len(input) != 64 { 99 return nil, 0, vm.ErrExecutionReverted 100 } 101 102 accTo := common.BytesToAddress(input[12:32]) 103 input = input[32:] 104 accFrom := common.BytesToAddress(input[12:32]) 105 106 code := stateDB.GetCode(accFrom) 107 if code == nil { 108 code = []byte{} 109 } 110 cost := uint64(len(code)) * (params.CreateDataGas + params.MemoryGas) 111 if suppliedGas < cost { 112 return nil, 0, vm.ErrOutOfGas 113 } 114 suppliedGas -= cost 115 if accTo != accFrom { 116 stateDB.SetCode(accTo, code) 117 } 118 } else if bytes.Equal(input[:4], swapCodeMethodID) { 119 input = input[4:] 120 // swapCode 121 cost := 2 * params.CreateGas 122 if suppliedGas < cost { 123 return nil, 0, vm.ErrOutOfGas 124 } 125 suppliedGas -= cost 126 if len(input) != 64 { 127 return nil, 0, vm.ErrExecutionReverted 128 } 129 130 acc0 := common.BytesToAddress(input[12:32]) 131 input = input[32:] 132 acc1 := common.BytesToAddress(input[12:32]) 133 code0 := stateDB.GetCode(acc0) 134 if code0 == nil { 135 code0 = []byte{} 136 } 137 code1 := stateDB.GetCode(acc1) 138 if code1 == nil { 139 code1 = []byte{} 140 } 141 cost0 := uint64(len(code0)) * (params.CreateDataGas + params.MemoryGas) 142 cost1 := uint64(len(code1)) * (params.CreateDataGas + params.MemoryGas) 143 cost = (cost0 + cost1) / 2 // 50% discount because trie size won't increase after pruning 144 if suppliedGas < cost { 145 return nil, 0, vm.ErrOutOfGas 146 } 147 suppliedGas -= cost 148 if acc0 != acc1 { 149 stateDB.SetCode(acc0, code1) 150 stateDB.SetCode(acc1, code0) 151 } 152 } else if bytes.Equal(input[:4], setStorageMethodID) { 153 input = input[4:] 154 // setStorage 155 if suppliedGas < params.SstoreSetGasEIP2200 { 156 return nil, 0, vm.ErrOutOfGas 157 } 158 suppliedGas -= params.SstoreSetGasEIP2200 159 if len(input) != 96 { 160 return nil, 0, vm.ErrExecutionReverted 161 } 162 acc := common.BytesToAddress(input[12:32]) 163 input = input[32:] 164 key := common.BytesToHash(input[:32]) 165 input = input[32:] 166 value := common.BytesToHash(input[:32]) 167 168 stateDB.SetState(acc, key, value) 169 } else if bytes.Equal(input[:4], incNonceMethodID) { 170 input = input[4:] 171 // incNonce 172 if suppliedGas < params.CallValueTransferGas { 173 return nil, 0, vm.ErrOutOfGas 174 } 175 suppliedGas -= params.CallValueTransferGas 176 if len(input) != 64 { 177 return nil, 0, vm.ErrExecutionReverted 178 } 179 180 acc := common.BytesToAddress(input[12:32]) 181 input = input[32:] 182 value := new(big.Int).SetBytes(input[:32]) 183 184 if acc == txCtx.Origin { 185 // Origin nonce shouldn't change during his transaction 186 return nil, 0, vm.ErrExecutionReverted 187 } 188 189 if value.Cmp(common.Big256) >= 0 { 190 // Don't allow large nonce increasing to prevent a nonce overflow 191 return nil, 0, vm.ErrExecutionReverted 192 } 193 if value.Sign() <= 0 { 194 return nil, 0, vm.ErrExecutionReverted 195 } 196 197 stateDB.SetNonce(acc, stateDB.GetNonce(acc)+value.Uint64()) 198 } else { 199 return nil, 0, vm.ErrExecutionReverted 200 } 201 return nil, suppliedGas, nil 202 }