github.com/datachainlab/burrow@v0.25.0/execution/evm/snative_test.go (about) 1 // Copyright 2017 Monax Industries Limited 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package evm 16 17 import ( 18 "encoding/hex" 19 "testing" 20 21 "github.com/stretchr/testify/require" 22 23 "strings" 24 25 "github.com/hyperledger/burrow/acm" 26 . "github.com/hyperledger/burrow/binary" 27 "github.com/hyperledger/burrow/crypto" 28 "github.com/hyperledger/burrow/crypto/sha3" 29 "github.com/hyperledger/burrow/execution/errors" 30 "github.com/hyperledger/burrow/execution/evm/abi" 31 "github.com/hyperledger/burrow/execution/evm/asm/bc" 32 "github.com/hyperledger/burrow/permission" 33 "github.com/stretchr/testify/assert" 34 ) 35 36 // Compiling the Permissions solidity contract at 37 // (generated by with 'make snatives' function) and passing to 38 // https://ethereum.github.io/browser-solidity (toggle details to get list) 39 // yields: 40 // Keep this updated to drive TestPermissionsContractSignatures 41 const compiledSigs = ` 42 7d72aa65 addRole(address,string) 43 1bfe0308 removeRole(address,string) 44 217fe6c6 hasRole(address,string) 45 dbd4a8ea setBase(address,uint64,bool) 46 b7d4dc0d unsetBase(address,uint64) 47 225b6574 hasBase(address,uint64) 48 c4bc7b70 setGlobal(uint64,bool) 49 ` 50 51 func TestPermissionsContractSignatures(t *testing.T) { 52 contract := SNativeContracts()["Permissions"] 53 54 nFuncs := len(contract.functions) 55 56 sigMap := idToSignatureMap() 57 58 assert.Len(t, sigMap, nFuncs, 59 "Permissions contract defines %s functions so we need %s "+ 60 "signatures in compiledSigs", 61 nFuncs, nFuncs) 62 63 for funcID, signature := range sigMap { 64 assertFunctionIDSignature(t, contract, funcID, signature) 65 } 66 } 67 68 func TestSNativeContractDescription_Dispatch(t *testing.T) { 69 contract := SNativeContracts()["Permissions"] 70 st := newAppState() 71 caller := &acm.Account{ 72 Address: crypto.Address{1, 1, 1}, 73 } 74 grantee := &acm.Account{ 75 Address: crypto.Address{2, 2, 2}, 76 } 77 require.NoError(t, st.UpdateAccount(caller)) 78 require.NoError(t, st.UpdateAccount(grantee)) 79 cache := NewState(st, blockHashGetter) 80 81 function, err := contract.FunctionByName("addRole") 82 if err != nil { 83 t.Fatalf("Could not get function: %s", err) 84 } 85 funcID := function.Abi.FunctionID 86 gas := uint64(1000) 87 88 // Should fail since we have no permissions 89 retValue, err := contract.Dispatch(cache, caller.Address, bc.MustSplice(funcID[:], grantee.Address, 90 permFlagToWord256(permission.CreateAccount)), &gas, logger) 91 if !assert.Error(t, err, "Should fail due to lack of permissions") { 92 return 93 } 94 assert.IsType(t, err, errors.LacksSNativePermission{}) 95 96 // Grant all permissions and dispatch should success 97 cache.SetPermission(caller.Address, permission.AddRole, true) 98 require.NoError(t, cache.Error()) 99 retValue, err = contract.Dispatch(cache, caller.Address, bc.MustSplice(funcID[:], 100 grantee.Address.Word256(), permFlagToWord256(permission.CreateAccount)), &gas, logger) 101 assert.NoError(t, err) 102 assert.Equal(t, retValue, LeftPadBytes([]byte{1}, 32)) 103 } 104 105 func TestSNativeContractDescription_Address(t *testing.T) { 106 contract := NewSNativeContract("A comment", 107 "CoolButVeryLongNamedContractOfDoom") 108 assert.Equal(t, sha3.Sha3(([]byte)(contract.Name))[12:], contract.Address().Bytes()) 109 } 110 111 // 112 // Helpers 113 // 114 func assertFunctionIDSignature(t *testing.T, contract *SNativeContractDescription, 115 funcIDHex string, expectedSignature string) { 116 fromHex := funcIDFromHex(t, funcIDHex) 117 function, err := contract.FunctionByID(fromHex) 118 assert.NoError(t, err, 119 "Error retrieving SNativeFunctionDescription with ID %s", funcIDHex) 120 if err == nil { 121 assert.Equal(t, expectedSignature, function.Signature()) 122 } 123 } 124 125 func funcIDFromHex(t *testing.T, hexString string) (funcID abi.FunctionID) { 126 bs, err := hex.DecodeString(hexString) 127 assert.NoError(t, err, "Could not decode hex string '%s'", hexString) 128 if len(bs) != 4 { 129 t.Fatalf("FunctionSelector must be 4 bytes but '%s' is %v bytes", hexString, 130 len(bs)) 131 } 132 copy(funcID[:], bs) 133 return 134 } 135 136 func permFlagToWord256(permFlag permission.PermFlag) Word256 { 137 return Uint64ToWord256(uint64(permFlag)) 138 } 139 140 func allAccountPermissions() permission.AccountPermissions { 141 return permission.AccountPermissions{ 142 Base: permission.BasePermissions{ 143 Perms: permission.AllPermFlags, 144 SetBit: permission.AllPermFlags, 145 }, 146 Roles: []string{}, 147 } 148 } 149 150 // turns the solidity compiler function summary into a map to drive signature 151 // test 152 func idToSignatureMap() map[string]string { 153 sigMap := make(map[string]string) 154 lines := strings.Split(compiledSigs, "\n") 155 for _, line := range lines { 156 trimmed := strings.Trim(line, " \t") 157 if trimmed != "" { 158 idSig := strings.Split(trimmed, " ") 159 sigMap[idSig[0]] = idSig[1] 160 } 161 } 162 return sigMap 163 }