github.com/MetalBlockchain/subnet-evm@v0.4.9/precompile/utils.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package precompile 5 6 import ( 7 "fmt" 8 "regexp" 9 10 "github.com/MetalBlockchain/subnet-evm/vmerrs" 11 "github.com/ethereum/go-ethereum/common" 12 "github.com/ethereum/go-ethereum/crypto" 13 ) 14 15 var functionSignatureRegex = regexp.MustCompile(`[\w]+\(((([\w]+)?)|((([\w]+),)+([\w]+)))\)`) 16 17 // CalculateFunctionSelector returns the 4 byte function selector that results from [functionSignature] 18 // Ex. the function setBalance(addr address, balance uint256) should be passed in as the string: 19 // "setBalance(address,uint256)" 20 func CalculateFunctionSelector(functionSignature string) []byte { 21 if !functionSignatureRegex.MatchString(functionSignature) { 22 panic(fmt.Errorf("invalid function signature: %q", functionSignature)) 23 } 24 hash := crypto.Keccak256([]byte(functionSignature)) 25 return hash[:4] 26 } 27 28 // deductGas checks if [suppliedGas] is sufficient against [requiredGas] and deducts [requiredGas] from [suppliedGas]. 29 func deductGas(suppliedGas uint64, requiredGas uint64) (uint64, error) { 30 if suppliedGas < requiredGas { 31 return 0, vmerrs.ErrOutOfGas 32 } 33 return suppliedGas - requiredGas, nil 34 } 35 36 // packOrderedHashesWithSelector packs the function selector and ordered list of hashes into [dst] 37 // byte slice. 38 // assumes that [dst] has sufficient room for [functionSelector] and [hashes]. 39 func packOrderedHashesWithSelector(dst []byte, functionSelector []byte, hashes []common.Hash) { 40 copy(dst[:len(functionSelector)], functionSelector) 41 packOrderedHashes(dst[len(functionSelector):], hashes) 42 } 43 44 // packOrderedHashes packs the ordered list of [hashes] into the [dst] byte buffer. 45 // assumes that [dst] has sufficient space to pack [hashes] or else this function will panic. 46 func packOrderedHashes(dst []byte, hashes []common.Hash) { 47 if len(dst) != len(hashes)*common.HashLength { 48 panic(fmt.Sprintf("destination byte buffer has insufficient length (%d) for %d hashes", len(dst), len(hashes))) 49 } 50 51 var ( 52 start = 0 53 end = common.HashLength 54 ) 55 for _, hash := range hashes { 56 copy(dst[start:end], hash.Bytes()) 57 start += common.HashLength 58 end += common.HashLength 59 } 60 } 61 62 // returnPackedHash returns packed the byte slice with common.HashLength from [packed] 63 // at the given [index]. 64 // Assumes that [packed] is composed entirely of packed 32 byte segments. 65 func returnPackedHash(packed []byte, index int) []byte { 66 start := common.HashLength * index 67 end := start + common.HashLength 68 return packed[start:end] 69 }