github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/call/find_test.go (about) 1 package call 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/abi" 8 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 9 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/parser" 10 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 12 ethAbi "github.com/ethereum/go-ethereum/accounts/abi" 13 ) 14 15 var abiSource = ` 16 [ 17 { 18 "encoding": "0xa175b638", 19 "inputs": [ 20 { 21 "name": "_value", 22 "type": "bool" 23 } 24 ], 25 "name": "setShouldReject", 26 "outputs": [], 27 "signature": "setShouldReject(bool)", 28 "type": "function" 29 }, 30 { 31 "constant": true, 32 "encoding": "0x01ffc9a7", 33 "inputs": [ 34 { 35 "name": "interfaceID", 36 "type": "bytes4" 37 } 38 ], 39 "name": "supportsInterface", 40 "outputs": [ 41 { 42 "name": "ret_0", 43 "type": "bool" 44 } 45 ], 46 "signature": "supportsInterface(bytes4)", 47 "type": "function" 48 }, 49 { 50 "constant": true, 51 "encoding": "0x0e89341c", 52 "inputs": [ 53 { 54 "name": "_id", 55 "type": "uint256" 56 } 57 ], 58 "name": "uri", 59 "outputs": [ 60 { 61 "name": "memory", 62 "type": "string" 63 } 64 ], 65 "signature": "uri(uint256)", 66 "type": "function" 67 } 68 ] 69 ` 70 71 // This comes from go-ethereum's abi_test.go, we will use it to 72 // test packing 73 const packTestAbiSource = ` 74 [ 75 { "type" : "function", "name" : ""}, 76 { "type" : "function", "name" : "string", "inputs" : [ { "name" : "inputs", "type" : "string" } ] }, 77 { "type" : "function", "name" : "bool", "inputs" : [ { "name" : "inputs", "type" : "bool" } ] }, 78 { "type" : "function", "name" : "address", "inputs" : [ { "name" : "inputs", "type" : "address" } ] }, 79 { "type" : "function", "name" : "uint64", "inputs" : [ { "name" : "inputs", "type" : "uint64" } ] }, 80 { "type" : "function", "name" : "uint256", "inputs" : [ { "name" : "inputs", "type" : "uint256" } ] }, 81 { "type" : "function", "name" : "int8", "inputs" : [ { "name" : "inputs", "type" : "int8" } ] }, 82 { "type" : "function", "name" : "int64", "inputs" : [ { "name" : "inputs", "type" : "int64" } ] }, 83 { "type" : "function", "name" : "int256", "inputs" : [ { "name" : "inputs", "type" : "int256" } ] }, 84 { "type" : "function", "name" : "bytes4", "inputs" : [ { "name" : "inputs", "type" : "bytes4" } ] }, 85 { "type" : "function", "name" : "bytes32", "inputs" : [ { "name" : "inputs", "type" : "bytes32" } ] } 86 ]` 87 88 var testAbi ethAbi.ABI 89 var abiMap abi.SelectorSyncMap 90 var packTestAbi ethAbi.ABI 91 92 func init() { 93 var err error 94 testAbi, err = ethAbi.JSON(strings.NewReader(abiSource)) 95 if err != nil { 96 panic(err) 97 } 98 99 testHelperAbisFromJson(&testAbi, &abiMap) 100 101 packTestAbi, err = ethAbi.JSON(strings.NewReader(packTestAbiSource)) 102 if err != nil { 103 panic(err) 104 } 105 } 106 107 func testHelperAbisFromJson(parsedAbi *ethAbi.ABI, abiMap *abi.SelectorSyncMap) { 108 for _, method := range parsedAbi.Methods { 109 encoding := "0x" + strings.ToLower(base.Bytes2Hex(method.ID)) 110 abiMap.SetValue(encoding, types.FunctionFromAbiMethod(&method)) 111 } 112 } 113 114 func Test_findAbiFunction(t *testing.T) { 115 call := &parser.FunctionContractCall{ 116 Name: "setShouldReject", 117 Arguments: []*parser.ContractArgument{ 118 { 119 Boolean: utils.PointerOf(parser.ArgBool(true)), 120 }, 121 }, 122 } 123 124 result, hints, err := FindAbiFunction(FindByName, call.Name, call.Arguments, &abiMap) 125 if err != nil { 126 t.Fatal(err) 127 } 128 wanted := testAbi.Methods["setShouldReject"] 129 130 if result.Signature != wanted.Sig { 131 t.Fatal("wanted", wanted.Sig, "got", result.Signature) 132 } 133 134 if len(hints) > 0 { 135 t.Fatal("expected no hints") 136 } 137 138 // Expect hints 139 call = &parser.FunctionContractCall{ 140 Name: "setShouldReject", 141 Arguments: []*parser.ContractArgument{}, 142 } 143 144 result, hints, err = FindAbiFunction(FindByName, call.Name, call.Arguments, &abiMap) 145 if err != nil { 146 t.Fatal(err) 147 } 148 149 if result != nil { 150 t.Fatal("expected no result") 151 } 152 153 if len(hints) != 1 { 154 t.Fatal("expected single hint", hints) 155 } 156 157 hint := hints[0] 158 if hint != "setShouldReject(bool)" { 159 t.Fatal("wrong hint:", hint) 160 } 161 162 // Expect no match 163 call = &parser.FunctionContractCall{ 164 Name: "somethingElse", 165 Arguments: []*parser.ContractArgument{}, 166 } 167 168 result, hints, err = FindAbiFunction(FindByName, call.Name, call.Arguments, &abiMap) 169 if err != nil { 170 t.Fatal(err) 171 } 172 173 if result != nil { 174 t.Fatal("expected no result") 175 } 176 177 if len(hints) != 0 { 178 t.Fatal("expected no hints") 179 } 180 } 181 182 func Test_findAbiFunctionBySelector(t *testing.T) { 183 call := &parser.SelectorContractCall{ 184 Selector: parser.Selector{ 185 Value: "0xa175b638", 186 }, 187 Arguments: []*parser.ContractArgument{ 188 { 189 Boolean: utils.PointerOf(parser.ArgBool(true)), 190 }, 191 }, 192 } 193 194 result, hints, err := FindAbiFunction(FindBySelector, call.Selector.Value, call.Arguments, &abiMap) 195 if err != nil { 196 t.Fatal(err) 197 } 198 wanted := testAbi.Methods["setShouldReject"] 199 200 if result.Signature != wanted.Sig { 201 t.Fatal("wanted", wanted.Sig, "got", result.Signature) 202 } 203 204 if len(hints) > 0 { 205 t.Fatal("expected no hints") 206 } 207 208 // Expect hints 209 call = &parser.SelectorContractCall{ 210 Selector: parser.Selector{ 211 Value: "0xa175b638", 212 }, 213 Arguments: []*parser.ContractArgument{}, 214 } 215 216 result, hints, err = FindAbiFunction(FindBySelector, call.Selector.Value, call.Arguments, &abiMap) 217 if err != nil { 218 t.Fatal(err) 219 } 220 221 if result != nil { 222 t.Fatal("expected no result") 223 } 224 225 if len(hints) != 1 { 226 t.Fatal("expected single hint", hints) 227 } 228 229 hint := hints[0] 230 if hint != "setShouldReject(bool)" { 231 t.Fatal("wrong hint:", hint) 232 } 233 234 // Expect no match 235 call = &parser.SelectorContractCall{ 236 Selector: parser.Selector{ 237 Value: "0xf175b639", 238 }, 239 Arguments: []*parser.ContractArgument{}, 240 } 241 242 result, hints, err = FindAbiFunction(FindBySelector, call.Selector.Value, call.Arguments, &abiMap) 243 if err != nil { 244 t.Fatal(err) 245 } 246 247 if result != nil { 248 t.Fatal("expected no result") 249 } 250 251 if len(hints) != 0 { 252 t.Fatal("expected no hints") 253 } 254 } 255 256 func Test_findAbiFunctionMisleading(t *testing.T) { 257 // This test makes sure we choose the right function 258 // when given two very similar ones. In this case, it's 259 // transfer(bytes32, address) and transfer(address, address). 260 parsedAbi, err := ethAbi.JSON(strings.NewReader(` 261 [ 262 { "type" : "function", "name" : "transfer", "inputs" : [ { "name" : "from", "type" : "bytes32" }, { "name" : "to", "type" : "address" } ] }, 263 { "type" : "function", "name" : "transfer", "inputs" : [ { "name" : "from", "type" : "address" }, { "name" : "to", "type" : "address" } ] } 264 ] 265 `)) 266 if err != nil { 267 t.Fatal(err) 268 } 269 270 testHelperAbisFromJson(&parsedAbi, &abiMap) 271 272 call := &parser.FunctionContractCall{ 273 Name: "transfer", 274 Arguments: []*parser.ContractArgument{ 275 { 276 Hex: &parser.ArgHex{ 277 Address: utils.PointerOf(base.HexToAddress("0x6B175474E89094C44Da98b954EedeAC495271d0F")), 278 }, 279 }, 280 { 281 Hex: &parser.ArgHex{ 282 Address: utils.PointerOf(base.HexToAddress("0x6B175474E89094C44Da98b954EedeAC495271d0F")), 283 }, 284 }, 285 }, 286 } 287 288 result, hints, err := FindAbiFunction(FindByName, call.Name, call.Arguments, &abiMap) 289 if err != nil { 290 t.Fatal(err) 291 } 292 wanted := parsedAbi.Methods["transfer0"] 293 if result == nil { 294 t.Fatal("did not find anything") 295 } 296 if result.Signature != wanted.Sig { 297 t.Fatal("found wrong function:", result.Signature) 298 } 299 if len(hints) > 0 { 300 t.Fatal("expected no hints:", hints) 301 } 302 }