github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/signer/core/signed_data_test.go (about) 1 package core_test 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "path" 9 "strings" 10 "testing" 11 12 "github.com/bigzoro/my_simplechain/accounts/keystore" 13 "github.com/bigzoro/my_simplechain/common" 14 "github.com/bigzoro/my_simplechain/common/hexutil" 15 "github.com/bigzoro/my_simplechain/common/math" 16 "github.com/bigzoro/my_simplechain/crypto" 17 "github.com/bigzoro/my_simplechain/signer/core" 18 ) 19 20 var typesStandard = core.Types{ 21 "EIP712Domain": { 22 { 23 Name: "name", 24 Type: "string", 25 }, 26 { 27 Name: "version", 28 Type: "string", 29 }, 30 { 31 Name: "chainId", 32 Type: "uint256", 33 }, 34 { 35 Name: "verifyingContract", 36 Type: "address", 37 }, 38 }, 39 "Person": { 40 { 41 Name: "name", 42 Type: "string", 43 }, 44 { 45 Name: "wallet", 46 Type: "address", 47 }, 48 }, 49 "Mail": { 50 { 51 Name: "from", 52 Type: "Person", 53 }, 54 { 55 Name: "to", 56 Type: "Person", 57 }, 58 { 59 Name: "contents", 60 Type: "string", 61 }, 62 }, 63 } 64 65 var jsonTypedData = ` 66 { 67 "types": { 68 "EIP712Domain": [ 69 { 70 "name": "name", 71 "type": "string" 72 }, 73 { 74 "name": "version", 75 "type": "string" 76 }, 77 { 78 "name": "chainId", 79 "type": "uint256" 80 }, 81 { 82 "name": "verifyingContract", 83 "type": "address" 84 } 85 ], 86 "Person": [ 87 { 88 "name": "name", 89 "type": "string" 90 }, 91 { 92 "name": "test", 93 "type": "uint8" 94 }, 95 { 96 "name": "wallet", 97 "type": "address" 98 } 99 ], 100 "Mail": [ 101 { 102 "name": "from", 103 "type": "Person" 104 }, 105 { 106 "name": "to", 107 "type": "Person" 108 }, 109 { 110 "name": "contents", 111 "type": "string" 112 } 113 ] 114 }, 115 "primaryType": "Mail", 116 "domain": { 117 "name": "Ether Mail", 118 "version": "1", 119 "chainId": "1", 120 "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 121 }, 122 "message": { 123 "from": { 124 "name": "Cow", 125 "test": 3, 126 "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 127 }, 128 "to": { 129 "name": "Bob", 130 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 131 }, 132 "contents": "Hello, Bob!" 133 } 134 } 135 ` 136 137 const primaryType = "Mail" 138 139 var domainStandard = core.TypedDataDomain{ 140 "Ether Mail", 141 "1", 142 math.NewHexOrDecimal256(1), 143 "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", 144 "", 145 } 146 147 var messageStandard = map[string]interface{}{ 148 "from": map[string]interface{}{ 149 "name": "Cow", 150 "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", 151 }, 152 "to": map[string]interface{}{ 153 "name": "Bob", 154 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", 155 }, 156 "contents": "Hello, Bob!", 157 } 158 159 var typedData = core.TypedData{ 160 Types: typesStandard, 161 PrimaryType: primaryType, 162 Domain: domainStandard, 163 Message: messageStandard, 164 } 165 166 func TestSignData(t *testing.T) { 167 api, control := setup(t) 168 //Create two accounts 169 createAccount(control, api, t) 170 createAccount(control, api, t) 171 control.approveCh <- "1" 172 list, err := api.List(context.Background()) 173 if err != nil { 174 t.Fatal(err) 175 } 176 a := common.NewMixedcaseAddress(list[0]) 177 178 control.approveCh <- "Y" 179 control.inputCh <- "wrongpassword" 180 signature, err := api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 181 if signature != nil { 182 t.Errorf("Expected nil-data, got %x", signature) 183 } 184 if err != keystore.ErrDecrypt { 185 t.Errorf("Expected ErrLocked! '%v'", err) 186 } 187 control.approveCh <- "No way" 188 signature, err = api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 189 if signature != nil { 190 t.Errorf("Expected nil-data, got %x", signature) 191 } 192 if err != core.ErrRequestDenied { 193 t.Errorf("Expected ErrRequestDenied! '%v'", err) 194 } 195 // text/plain 196 control.approveCh <- "Y" 197 control.inputCh <- "a_long_password" 198 signature, err = api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 199 if err != nil { 200 t.Fatal(err) 201 } 202 if signature == nil || len(signature) != 65 { 203 t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) 204 } 205 // data/typed 206 control.approveCh <- "Y" 207 control.inputCh <- "a_long_password" 208 signature, err = api.SignTypedData(context.Background(), a, typedData) 209 if err != nil { 210 t.Fatal(err) 211 } 212 if signature == nil || len(signature) != 65 { 213 t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) 214 } 215 } 216 217 func TestDomainChainId(t *testing.T) { 218 withoutChainID := core.TypedData{ 219 Types: core.Types{ 220 "EIP712Domain": []core.Type{ 221 {Name: "name", Type: "string"}, 222 }, 223 }, 224 Domain: core.TypedDataDomain{ 225 Name: "test", 226 }, 227 } 228 229 if _, ok := withoutChainID.Domain.Map()["chainId"]; ok { 230 t.Errorf("Expected the chainId key to not be present in the domain map") 231 } 232 withChainID := core.TypedData{ 233 Types: core.Types{ 234 "EIP712Domain": []core.Type{ 235 {Name: "name", Type: "string"}, 236 {Name: "chainId", Type: "uint256"}, 237 }, 238 }, 239 Domain: core.TypedDataDomain{ 240 Name: "test", 241 ChainId: math.NewHexOrDecimal256(1), 242 }, 243 } 244 245 if _, ok := withChainID.Domain.Map()["chainId"]; !ok { 246 t.Errorf("Expected the chainId key be present in the domain map") 247 } 248 } 249 250 func TestHashStruct(t *testing.T) { 251 hash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) 252 if err != nil { 253 t.Fatal(err) 254 } 255 mainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 256 if mainHash != "0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e" { 257 t.Errorf("Expected different hashStruct result (got %s)", mainHash) 258 } 259 260 hash, err = typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) 261 if err != nil { 262 t.Error(err) 263 } 264 domainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 265 if domainHash != "0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f" { 266 t.Errorf("Expected different domain hashStruct result (got %s)", domainHash) 267 } 268 } 269 270 func TestEncodeType(t *testing.T) { 271 domainTypeEncoding := string(typedData.EncodeType("EIP712Domain")) 272 if domainTypeEncoding != "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" { 273 t.Errorf("Expected different encodeType result (got %s)", domainTypeEncoding) 274 } 275 276 mailTypeEncoding := string(typedData.EncodeType(typedData.PrimaryType)) 277 if mailTypeEncoding != "Mail(Person from,Person to,string contents)Person(string name,address wallet)" { 278 t.Errorf("Expected different encodeType result (got %s)", mailTypeEncoding) 279 } 280 } 281 282 func TestTypeHash(t *testing.T) { 283 mailTypeHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.TypeHash(typedData.PrimaryType))) 284 if mailTypeHash != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2" { 285 t.Errorf("Expected different typeHash result (got %s)", mailTypeHash) 286 } 287 } 288 289 func TestEncodeData(t *testing.T) { 290 hash, err := typedData.EncodeData(typedData.PrimaryType, typedData.Message, 0) 291 if err != nil { 292 t.Fatal(err) 293 } 294 dataEncoding := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 295 if dataEncoding != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8" { 296 t.Errorf("Expected different encodeData result (got %s)", dataEncoding) 297 } 298 } 299 300 func TestFormatter(t *testing.T) { 301 var d core.TypedData 302 err := json.Unmarshal([]byte(jsonTypedData), &d) 303 if err != nil { 304 t.Fatalf("unmarshalling failed '%v'", err) 305 } 306 formatted, _ := d.Format() 307 for _, item := range formatted { 308 t.Logf("'%v'\n", item.Pprint(0)) 309 } 310 311 j, _ := json.Marshal(formatted) 312 t.Logf("'%v'\n", string(j)) 313 } 314 315 func sign(typedData core.TypedData) ([]byte, []byte, error) { 316 domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) 317 if err != nil { 318 return nil, nil, err 319 } 320 typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) 321 if err != nil { 322 return nil, nil, err 323 } 324 rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) 325 sighash := crypto.Keccak256(rawData) 326 return typedDataHash, sighash, nil 327 } 328 329 func TestJsonFiles(t *testing.T) { 330 testfiles, err := ioutil.ReadDir("testdata/") 331 if err != nil { 332 t.Fatalf("failed reading files: %v", err) 333 } 334 for i, fInfo := range testfiles { 335 if !strings.HasSuffix(fInfo.Name(), "json") { 336 continue 337 } 338 expectedFailure := strings.HasPrefix(fInfo.Name(), "expfail") 339 data, err := ioutil.ReadFile(path.Join("testdata", fInfo.Name())) 340 if err != nil { 341 t.Errorf("Failed to read file %v: %v", fInfo.Name(), err) 342 continue 343 } 344 var typedData core.TypedData 345 err = json.Unmarshal(data, &typedData) 346 if err != nil { 347 t.Errorf("Test %d, file %v, json unmarshalling failed: %v", i, fInfo.Name(), err) 348 continue 349 } 350 _, _, err = sign(typedData) 351 t.Logf("Error %v\n", err) 352 if err != nil && !expectedFailure { 353 t.Errorf("Test %d failed, file %v: %v", i, fInfo.Name(), err) 354 } 355 if expectedFailure && err == nil { 356 t.Errorf("Test %d succeeded (expected failure), file %v: %v", i, fInfo.Name(), err) 357 } 358 } 359 } 360 361 // TestFuzzerFiles tests some files that have been found by fuzzing to cause 362 // crashes or hangs. 363 func TestFuzzerFiles(t *testing.T) { 364 corpusdir := path.Join("testdata", "fuzzing") 365 testfiles, err := ioutil.ReadDir(corpusdir) 366 if err != nil { 367 t.Fatalf("failed reading files: %v", err) 368 } 369 verbose := false 370 for i, fInfo := range testfiles { 371 data, err := ioutil.ReadFile(path.Join(corpusdir, fInfo.Name())) 372 if err != nil { 373 t.Errorf("Failed to read file %v: %v", fInfo.Name(), err) 374 continue 375 } 376 var typedData core.TypedData 377 err = json.Unmarshal(data, &typedData) 378 if err != nil { 379 t.Errorf("Test %d, file %v, json unmarshalling failed: %v", i, fInfo.Name(), err) 380 continue 381 } 382 _, err = typedData.EncodeData("EIP712Domain", typedData.Domain.Map(), 1) 383 if verbose && err != nil { 384 t.Logf("%d, EncodeData[1] err: %v\n", i, err) 385 } 386 _, err = typedData.EncodeData(typedData.PrimaryType, typedData.Message, 1) 387 if verbose && err != nil { 388 t.Logf("%d, EncodeData[2] err: %v\n", i, err) 389 } 390 typedData.Format() 391 } 392 }