github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/contracts/chequebook/cheque_test.go (about)

     1  // Copyright 2016 The Spectrum Authors
     2  // This file is part of the Spectrum library.
     3  //
     4  // The Spectrum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser 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  // The Spectrum library 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 Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package chequebook
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"math/big"
    22  	"os"
    23  	"path/filepath"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/SmartMeshFoundation/Spectrum/accounts/abi/bind"
    28  	"github.com/SmartMeshFoundation/Spectrum/accounts/abi/bind/backends"
    29  	"github.com/SmartMeshFoundation/Spectrum/common"
    30  	"github.com/SmartMeshFoundation/Spectrum/contracts/chequebook/contract"
    31  	"github.com/SmartMeshFoundation/Spectrum/core"
    32  	"github.com/SmartMeshFoundation/Spectrum/crypto"
    33  )
    34  
    35  var (
    36  	key0, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    37  	key1, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
    38  	key2, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
    39  	addr0   = crypto.PubkeyToAddress(key0.PublicKey)
    40  	addr1   = crypto.PubkeyToAddress(key1.PublicKey)
    41  	addr2   = crypto.PubkeyToAddress(key2.PublicKey)
    42  )
    43  
    44  func newTestBackend() *backends.SimulatedBackend {
    45  	return backends.NewSimulatedBackend(core.GenesisAlloc{
    46  		addr0: {Balance: big.NewInt(1000000000)},
    47  		addr1: {Balance: big.NewInt(1000000000)},
    48  		addr2: {Balance: big.NewInt(1000000000)},
    49  	})
    50  }
    51  
    52  func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {
    53  	deployTransactor := bind.NewKeyedTransactor(prvKey)
    54  	deployTransactor.Value = amount
    55  	addr, _, _, err := contract.DeployChequebook(deployTransactor, backend)
    56  	if err != nil {
    57  		return common.Address{}, err
    58  	}
    59  	backend.Commit()
    60  	return addr, nil
    61  }
    62  
    63  func TestIssueAndReceive(t *testing.T) {
    64  	path := filepath.Join(os.TempDir(), "chequebook-test.json")
    65  	backend := newTestBackend()
    66  	addr0, err := deploy(key0, big.NewInt(0), backend)
    67  	if err != nil {
    68  		t.Fatalf("deploy contract: expected no error, got %v", err)
    69  	}
    70  	chbook, err := NewChequebook(path, addr0, key0, backend)
    71  	if err != nil {
    72  		t.Fatalf("expected no error, got %v", err)
    73  	}
    74  	chbook.sent[addr1] = new(big.Int).SetUint64(42)
    75  	amount := common.Big1
    76  
    77  	if _, err = chbook.Issue(addr1, amount); err == nil {
    78  		t.Fatalf("expected insufficient funds error, got none")
    79  	}
    80  
    81  	chbook.balance = new(big.Int).Set(common.Big1)
    82  	if chbook.Balance().Cmp(common.Big1) != 0 {
    83  		t.Fatalf("expected: %v, got %v", "0", chbook.Balance())
    84  	}
    85  
    86  	ch, err := chbook.Issue(addr1, amount)
    87  	if err != nil {
    88  		t.Fatalf("expected no error, got %v", err)
    89  	}
    90  
    91  	if chbook.Balance().Sign() != 0 {
    92  		t.Errorf("expected: %v, got %v", "0", chbook.Balance())
    93  	}
    94  
    95  	chbox, err := NewInbox(key1, addr0, addr1, &key0.PublicKey, backend)
    96  	if err != nil {
    97  		t.Fatalf("expected no error, got %v", err)
    98  	}
    99  
   100  	received, err := chbox.Receive(ch)
   101  	if err != nil {
   102  		t.Fatalf("expected no error, got %v", err)
   103  	}
   104  
   105  	if received.Cmp(big.NewInt(43)) != 0 {
   106  		t.Errorf("expected: %v, got %v", "43", received)
   107  	}
   108  
   109  }
   110  
   111  func TestCheckbookFile(t *testing.T) {
   112  	path := filepath.Join(os.TempDir(), "chequebook-test.json")
   113  	backend := newTestBackend()
   114  	chbook, err := NewChequebook(path, addr0, key0, backend)
   115  	if err != nil {
   116  		t.Fatalf("expected no error, got %v", err)
   117  	}
   118  	chbook.sent[addr1] = new(big.Int).SetUint64(42)
   119  	chbook.balance = new(big.Int).Set(common.Big1)
   120  
   121  	chbook.Save()
   122  
   123  	chbook, err = LoadChequebook(path, key0, backend, false)
   124  	if err != nil {
   125  		t.Fatalf("expected no error, got %v", err)
   126  	}
   127  	if chbook.Balance().Cmp(common.Big1) != 0 {
   128  		t.Errorf("expected: %v, got %v", "0", chbook.Balance())
   129  	}
   130  
   131  	var ch *Cheque
   132  	if ch, err = chbook.Issue(addr1, common.Big1); err != nil {
   133  		t.Fatalf("expected no error, got %v", err)
   134  	}
   135  	if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 {
   136  		t.Errorf("expected: %v, got %v", "0", ch.Amount)
   137  	}
   138  
   139  	err = chbook.Save()
   140  	if err != nil {
   141  		t.Fatalf("expected no error, got %v", err)
   142  	}
   143  }
   144  
   145  func TestVerifyErrors(t *testing.T) {
   146  	path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json")
   147  	backend := newTestBackend()
   148  	contr0, err := deploy(key0, common.Big2, backend)
   149  	if err != nil {
   150  		t.Errorf("expected no error, got %v", err)
   151  	}
   152  	chbook0, err := NewChequebook(path0, contr0, key0, backend)
   153  	if err != nil {
   154  		t.Errorf("expected no error, got %v", err)
   155  	}
   156  
   157  	path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json")
   158  	contr1, _ := deploy(key1, common.Big2, backend)
   159  	chbook1, err := NewChequebook(path1, contr1, key1, backend)
   160  	if err != nil {
   161  		t.Errorf("expected no error, got %v", err)
   162  	}
   163  
   164  	chbook0.sent[addr1] = new(big.Int).SetUint64(42)
   165  	chbook0.balance = new(big.Int).Set(common.Big2)
   166  	chbook1.balance = new(big.Int).Set(common.Big1)
   167  	amount := common.Big1
   168  	ch0, err := chbook0.Issue(addr1, amount)
   169  	if err != nil {
   170  		t.Fatalf("expected no error, got %v", err)
   171  	}
   172  
   173  	chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend)
   174  	if err != nil {
   175  		t.Fatalf("expected no error, got %v", err)
   176  	}
   177  
   178  	received, err := chbox.Receive(ch0)
   179  	if err != nil {
   180  		t.Fatalf("expected no error, got %v", err)
   181  	}
   182  
   183  	if received.Cmp(big.NewInt(43)) != 0 {
   184  		t.Errorf("expected: %v, got %v", "43", received)
   185  	}
   186  
   187  	ch1, err := chbook0.Issue(addr2, amount)
   188  	if err != nil {
   189  		t.Fatalf("expected no error, got %v", err)
   190  	}
   191  
   192  	received, err = chbox.Receive(ch1)
   193  	t.Logf("correct error: %v", err)
   194  	if err == nil {
   195  		t.Fatalf("expected receiver error, got none and value %v", received)
   196  	}
   197  
   198  	ch2, err := chbook1.Issue(addr1, amount)
   199  	if err != nil {
   200  		t.Fatalf("expected no error, got %v", err)
   201  	}
   202  	received, err = chbox.Receive(ch2)
   203  	t.Logf("correct error: %v", err)
   204  	if err == nil {
   205  		t.Fatalf("expected sender error, got none and value %v", received)
   206  	}
   207  
   208  	_, err = chbook1.Issue(addr1, new(big.Int).SetInt64(-1))
   209  	t.Logf("correct error: %v", err)
   210  	if err == nil {
   211  		t.Fatalf("expected incorrect amount error, got none")
   212  	}
   213  
   214  	received, err = chbox.Receive(ch0)
   215  	t.Logf("correct error: %v", err)
   216  	if err == nil {
   217  		t.Fatalf("expected incorrect amount error, got none and value %v", received)
   218  	}
   219  
   220  }
   221  
   222  func TestDeposit(t *testing.T) {
   223  	path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json")
   224  	backend := newTestBackend()
   225  	contr0, _ := deploy(key0, new(big.Int), backend)
   226  
   227  	chbook, err := NewChequebook(path0, contr0, key0, backend)
   228  	if err != nil {
   229  		t.Errorf("expected no error, got %v", err)
   230  	}
   231  
   232  	balance := new(big.Int).SetUint64(42)
   233  	chbook.Deposit(balance)
   234  	backend.Commit()
   235  	if chbook.Balance().Cmp(balance) != 0 {
   236  		t.Fatalf("expected balance %v, got %v", balance, chbook.Balance())
   237  	}
   238  
   239  	amount := common.Big1
   240  	_, err = chbook.Issue(addr1, amount)
   241  	if err != nil {
   242  		t.Fatalf("expected no error, got %v", err)
   243  	}
   244  	backend.Commit()
   245  	exp := new(big.Int).SetUint64(41)
   246  	if chbook.Balance().Cmp(exp) != 0 {
   247  		t.Fatalf("expected balance %v, got %v", exp, chbook.Balance())
   248  	}
   249  
   250  	// autodeposit on each issue
   251  	chbook.AutoDeposit(0, balance, balance)
   252  	_, err = chbook.Issue(addr1, amount)
   253  	if err != nil {
   254  		t.Fatalf("expected no error, got %v", err)
   255  	}
   256  	backend.Commit()
   257  	_, err = chbook.Issue(addr1, amount)
   258  	if err != nil {
   259  		t.Fatalf("expected no error, got %v", err)
   260  	}
   261  	backend.Commit()
   262  	if chbook.Balance().Cmp(balance) != 0 {
   263  		t.Fatalf("expected balance %v, got %v", balance, chbook.Balance())
   264  	}
   265  
   266  	// autodeposit off
   267  	chbook.AutoDeposit(0, common.Big0, balance)
   268  	_, err = chbook.Issue(addr1, amount)
   269  	if err != nil {
   270  		t.Fatalf("expected no error, got %v", err)
   271  	}
   272  	backend.Commit()
   273  	_, err = chbook.Issue(addr1, amount)
   274  	if err != nil {
   275  		t.Fatalf("expected no error, got %v", err)
   276  	}
   277  	backend.Commit()
   278  
   279  	exp = new(big.Int).SetUint64(40)
   280  	if chbook.Balance().Cmp(exp) != 0 {
   281  		t.Fatalf("expected balance %v, got %v", exp, chbook.Balance())
   282  	}
   283  
   284  	// autodeposit every 30ms if new cheque issued
   285  	interval := 30 * time.Millisecond
   286  	chbook.AutoDeposit(interval, common.Big1, balance)
   287  	_, err = chbook.Issue(addr1, amount)
   288  	if err != nil {
   289  		t.Fatalf("expected no error, got %v", err)
   290  	}
   291  	backend.Commit()
   292  	_, err = chbook.Issue(addr1, amount)
   293  	if err != nil {
   294  		t.Fatalf("expected no error, got %v", err)
   295  	}
   296  	backend.Commit()
   297  
   298  	exp = new(big.Int).SetUint64(38)
   299  	if chbook.Balance().Cmp(exp) != 0 {
   300  		t.Fatalf("expected balance %v, got %v", exp, chbook.Balance())
   301  	}
   302  
   303  	time.Sleep(3 * interval)
   304  	backend.Commit()
   305  	if chbook.Balance().Cmp(balance) != 0 {
   306  		t.Fatalf("expected balance %v, got %v", balance, chbook.Balance())
   307  	}
   308  
   309  	exp = new(big.Int).SetUint64(40)
   310  	chbook.AutoDeposit(4*interval, exp, balance)
   311  	_, err = chbook.Issue(addr1, amount)
   312  	if err != nil {
   313  		t.Fatalf("expected no error, got %v", err)
   314  	}
   315  	backend.Commit()
   316  	_, err = chbook.Issue(addr1, amount)
   317  	if err != nil {
   318  		t.Fatalf("expected no error, got %v", err)
   319  	}
   320  	time.Sleep(3 * interval)
   321  	backend.Commit()
   322  	if chbook.Balance().Cmp(exp) != 0 {
   323  		t.Fatalf("expected balance %v, got %v", exp, chbook.Balance())
   324  	}
   325  
   326  	_, err = chbook.Issue(addr1, amount)
   327  	if err != nil {
   328  		t.Fatalf("expected no error, got %v", err)
   329  	}
   330  	time.Sleep(1 * interval)
   331  	backend.Commit()
   332  
   333  	if chbook.Balance().Cmp(balance) != 0 {
   334  		t.Fatalf("expected balance %v, got %v", balance, chbook.Balance())
   335  	}
   336  
   337  	chbook.AutoDeposit(1*interval, common.Big0, balance)
   338  	chbook.Stop()
   339  
   340  	_, err = chbook.Issue(addr1, common.Big1)
   341  	if err != nil {
   342  		t.Fatalf("expected no error, got %v", err)
   343  	}
   344  	backend.Commit()
   345  
   346  	_, err = chbook.Issue(addr1, common.Big2)
   347  	if err != nil {
   348  		t.Fatalf("expected no error, got %v", err)
   349  	}
   350  
   351  	time.Sleep(1 * interval)
   352  	backend.Commit()
   353  
   354  	exp = new(big.Int).SetUint64(39)
   355  	if chbook.Balance().Cmp(exp) != 0 {
   356  		t.Fatalf("expected balance %v, got %v", exp, chbook.Balance())
   357  	}
   358  
   359  }
   360  
   361  func TestCash(t *testing.T) {
   362  	path := filepath.Join(os.TempDir(), "chequebook-test.json")
   363  	backend := newTestBackend()
   364  	contr0, _ := deploy(key0, common.Big2, backend)
   365  
   366  	chbook, err := NewChequebook(path, contr0, key0, backend)
   367  	if err != nil {
   368  		t.Errorf("expected no error, got %v", err)
   369  	}
   370  	chbook.sent[addr1] = new(big.Int).SetUint64(42)
   371  	amount := common.Big1
   372  	chbook.balance = new(big.Int).Set(common.Big1)
   373  	ch, err := chbook.Issue(addr1, amount)
   374  	if err != nil {
   375  		t.Fatalf("expected no error, got %v", err)
   376  	}
   377  	backend.Commit()
   378  	chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend)
   379  	if err != nil {
   380  		t.Fatalf("expected no error, got %v", err)
   381  	}
   382  
   383  	// cashing latest cheque
   384  	if _, err = chbox.Receive(ch); err != nil {
   385  		t.Fatalf("expected no error, got %v", err)
   386  	}
   387  	if _, err = ch.Cash(chbook.session); err != nil {
   388  		t.Fatal("Cash failed:", err)
   389  	}
   390  	backend.Commit()
   391  
   392  	chbook.balance = new(big.Int).Set(common.Big3)
   393  	ch0, err := chbook.Issue(addr1, amount)
   394  	if err != nil {
   395  		t.Fatalf("expected no error, got %v", err)
   396  	}
   397  	backend.Commit()
   398  	ch1, err := chbook.Issue(addr1, amount)
   399  	if err != nil {
   400  		t.Fatalf("expected no error, got %v", err)
   401  	}
   402  	backend.Commit()
   403  
   404  	interval := 10 * time.Millisecond
   405  	// setting autocash with interval of 10ms
   406  	chbox.AutoCash(interval, nil)
   407  	_, err = chbox.Receive(ch0)
   408  	if err != nil {
   409  		t.Fatalf("expected no error, got %v", err)
   410  	}
   411  	_, err = chbox.Receive(ch1)
   412  	if err != nil {
   413  		t.Fatalf("expected no error, got %v", err)
   414  	}
   415  	backend.Commit()
   416  	// after 3x interval time and 2 cheques received, exactly one cashing tx is sent
   417  	time.Sleep(4 * interval)
   418  	backend.Commit()
   419  
   420  	// after stopping autocash no more tx are sent
   421  	ch2, err := chbook.Issue(addr1, amount)
   422  	if err != nil {
   423  		t.Fatalf("expected no error, got %v", err)
   424  	}
   425  	chbox.Stop()
   426  	_, err = chbox.Receive(ch2)
   427  	if err != nil {
   428  		t.Fatalf("expected no error, got %v", err)
   429  	}
   430  	time.Sleep(2 * interval)
   431  	backend.Commit()
   432  
   433  	// autocash below 1
   434  	chbook.balance = big.NewInt(2)
   435  	chbox.AutoCash(0, common.Big1)
   436  
   437  	ch3, err := chbook.Issue(addr1, amount)
   438  	if err != nil {
   439  		t.Fatalf("expected no error, got %v", err)
   440  	}
   441  	backend.Commit()
   442  
   443  	ch4, err := chbook.Issue(addr1, amount)
   444  	if err != nil {
   445  		t.Fatalf("expected no error, got %v", err)
   446  	}
   447  	backend.Commit()
   448  
   449  	_, err = chbox.Receive(ch3)
   450  	if err != nil {
   451  		t.Fatalf("expected no error, got %v", err)
   452  	}
   453  	backend.Commit()
   454  	_, err = chbox.Receive(ch4)
   455  	if err != nil {
   456  		t.Fatalf("expected no error, got %v", err)
   457  	}
   458  	backend.Commit()
   459  
   460  	// autochash on receipt when maxUncashed is 0
   461  	chbook.balance = new(big.Int).Set(common.Big2)
   462  	chbox.AutoCash(0, common.Big0)
   463  
   464  	ch5, err := chbook.Issue(addr1, amount)
   465  	if err != nil {
   466  		t.Fatalf("expected no error, got %v", err)
   467  	}
   468  	backend.Commit()
   469  
   470  	ch6, err := chbook.Issue(addr1, amount)
   471  	if err != nil {
   472  		t.Fatalf("expected no error, got %v", err)
   473  	}
   474  
   475  	_, err = chbox.Receive(ch5)
   476  	if err != nil {
   477  		t.Fatalf("expected no error, got %v", err)
   478  	}
   479  	backend.Commit()
   480  
   481  	_, err = chbox.Receive(ch6)
   482  	if err != nil {
   483  		t.Fatalf("expected no error, got %v", err)
   484  	}
   485  	backend.Commit()
   486  
   487  }