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  }