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":   &copyCodeMethodID,
    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  }