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