github.com/ethersphere/bee/v2@v2.2.0/pkg/storageincentives/redistribution/redistribution_test.go (about)

     1  // Copyright 2022 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package redistribution_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"encoding/binary"
    11  	"errors"
    12  	"fmt"
    13  	"math/big"
    14  	"testing"
    15  
    16  	"github.com/ethereum/go-ethereum/common"
    17  	"github.com/ethereum/go-ethereum/core/types"
    18  	chaincfg "github.com/ethersphere/bee/v2/pkg/config"
    19  	"github.com/ethersphere/bee/v2/pkg/log"
    20  	"github.com/ethersphere/bee/v2/pkg/sctx"
    21  	"github.com/ethersphere/bee/v2/pkg/storageincentives/redistribution"
    22  	"github.com/ethersphere/bee/v2/pkg/swarm"
    23  	"github.com/ethersphere/bee/v2/pkg/transaction"
    24  	transactionMock "github.com/ethersphere/bee/v2/pkg/transaction/mock"
    25  	"github.com/ethersphere/bee/v2/pkg/util/abiutil"
    26  	"github.com/ethersphere/bee/v2/pkg/util/testutil"
    27  )
    28  
    29  var redistributionContractABI = abiutil.MustParseABI(chaincfg.Testnet.RedistributionABI)
    30  
    31  func randChunkInclusionProof(t *testing.T) redistribution.ChunkInclusionProof {
    32  	t.Helper()
    33  
    34  	return redistribution.ChunkInclusionProof{
    35  		ProofSegments:  []common.Hash{common.BytesToHash(testutil.RandBytes(t, 32))},
    36  		ProveSegment:   common.BytesToHash(testutil.RandBytes(t, 32)),
    37  		ProofSegments2: []common.Hash{common.BytesToHash(testutil.RandBytes(t, 32))},
    38  		ProveSegment2:  common.BytesToHash(testutil.RandBytes(t, 32)),
    39  		ProofSegments3: []common.Hash{common.BytesToHash(testutil.RandBytes(t, 32))},
    40  		PostageProof: redistribution.PostageProof{
    41  			Signature: testutil.RandBytes(t, 65),
    42  			PostageId: common.BytesToHash(testutil.RandBytes(t, 32)),
    43  			Index:     binary.BigEndian.Uint64(testutil.RandBytes(t, 8)),
    44  			TimeStamp: binary.BigEndian.Uint64(testutil.RandBytes(t, 8)),
    45  		},
    46  		ChunkSpan: 1,
    47  		SocProof:  []redistribution.SOCProof{},
    48  	}
    49  }
    50  
    51  func randChunkInclusionProofs(t *testing.T) redistribution.ChunkInclusionProofs {
    52  	t.Helper()
    53  
    54  	return redistribution.ChunkInclusionProofs{
    55  		A: randChunkInclusionProof(t),
    56  		B: randChunkInclusionProof(t),
    57  		C: randChunkInclusionProof(t),
    58  	}
    59  }
    60  
    61  func TestRedistribution(t *testing.T) {
    62  	t.Parallel()
    63  
    64  	ctx := context.Background()
    65  	ctx = sctx.SetGasPrice(ctx, big.NewInt(100))
    66  	owner := common.HexToAddress("abcd")
    67  	overlay := swarm.NewAddress(common.HexToHash("cbd").Bytes())
    68  	redistributionContractAddress := common.HexToAddress("ffff")
    69  	//nonce := common.BytesToHash(make([]byte, 32))
    70  	txHashDeposited := common.HexToHash("c3a7")
    71  
    72  	t.Run("IsPlaying - true", func(t *testing.T) {
    73  		t.Parallel()
    74  
    75  		depth := uint8(10)
    76  		expectedRes := big.NewInt(1)
    77  		contract := redistribution.New(
    78  			overlay,
    79  			owner,
    80  			log.Noop,
    81  			transactionMock.New(
    82  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
    83  					if *request.To == redistributionContractAddress {
    84  						return expectedRes.FillBytes(make([]byte, 32)), nil
    85  					}
    86  					return nil, errors.New("unexpected call")
    87  				}),
    88  			),
    89  			redistributionContractAddress,
    90  			redistributionContractABI,
    91  			false,
    92  		)
    93  
    94  		isPlaying, err := contract.IsPlaying(ctx, depth)
    95  		if err != nil {
    96  			t.Fatal(err)
    97  		}
    98  		if !isPlaying {
    99  			t.Fatal("expected playing")
   100  		}
   101  	})
   102  
   103  	t.Run("IsPlaying - false", func(t *testing.T) {
   104  		t.Parallel()
   105  
   106  		depth := uint8(10)
   107  
   108  		expectedRes := big.NewInt(0)
   109  		contract := redistribution.New(
   110  			overlay,
   111  			owner,
   112  			log.Noop,
   113  			transactionMock.New(
   114  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   115  					if *request.To == redistributionContractAddress {
   116  						return expectedRes.FillBytes(make([]byte, 32)), nil
   117  					}
   118  					return nil, errors.New("unexpected call")
   119  				}),
   120  			),
   121  			redistributionContractAddress,
   122  			redistributionContractABI,
   123  			false,
   124  		)
   125  
   126  		isPlaying, err := contract.IsPlaying(ctx, depth)
   127  		if err != nil {
   128  			t.Fatal(err)
   129  		}
   130  		if isPlaying {
   131  			t.Fatal("expected not playing")
   132  		}
   133  	})
   134  
   135  	t.Run("IsWinner - false", func(t *testing.T) {
   136  		t.Parallel()
   137  
   138  		expectedRes := big.NewInt(0)
   139  		contract := redistribution.New(
   140  			overlay,
   141  			owner,
   142  			log.Noop,
   143  			transactionMock.New(
   144  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   145  					if *request.To == redistributionContractAddress {
   146  						return expectedRes.FillBytes(make([]byte, 32)), nil
   147  					}
   148  					return nil, errors.New("unexpected call")
   149  				}),
   150  			),
   151  			redistributionContractAddress,
   152  			redistributionContractABI,
   153  			false,
   154  		)
   155  
   156  		isWinner, err := contract.IsWinner(ctx)
   157  		if err != nil {
   158  			t.Fatal(err)
   159  		}
   160  		if isWinner {
   161  			t.Fatalf("expected false, got %t", isWinner)
   162  		}
   163  	})
   164  
   165  	t.Run("IsWinner - true", func(t *testing.T) {
   166  		t.Parallel()
   167  
   168  		expectedRes := big.NewInt(1)
   169  		contract := redistribution.New(overlay, owner, log.Noop,
   170  			transactionMock.New(
   171  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   172  					if *request.To == redistributionContractAddress {
   173  						return expectedRes.FillBytes(make([]byte, 32)), nil
   174  					}
   175  					return nil, errors.New("unexpected call")
   176  				}),
   177  			),
   178  			redistributionContractAddress,
   179  			redistributionContractABI,
   180  			false,
   181  		)
   182  
   183  		isWinner, err := contract.IsWinner(ctx)
   184  		if err != nil {
   185  			t.Fatal(err)
   186  		}
   187  		if !isWinner {
   188  			t.Fatalf("expected true, got %t", isWinner)
   189  		}
   190  	})
   191  
   192  	t.Run("Claim", func(t *testing.T) {
   193  		t.Parallel()
   194  
   195  		proofs := randChunkInclusionProofs(t)
   196  
   197  		expectedCallData, err := redistributionContractABI.Pack("claim", proofs.A, proofs.B, proofs.C)
   198  		if err != nil {
   199  			t.Fatal(err)
   200  		}
   201  		contract := redistribution.New(
   202  			overlay,
   203  			owner,
   204  			log.Noop,
   205  			transactionMock.New(
   206  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   207  					if *request.To == redistributionContractAddress {
   208  						if !bytes.Equal(expectedCallData[:32], request.Data[:32]) {
   209  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   210  						}
   211  						return txHashDeposited, nil
   212  					}
   213  					return common.Hash{}, errors.New("sent to wrong contract")
   214  				}),
   215  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   216  					if txHash == txHashDeposited {
   217  						return &types.Receipt{
   218  							Status: 1,
   219  						}, nil
   220  					}
   221  					return nil, errors.New("unknown tx hash")
   222  				}),
   223  			),
   224  			redistributionContractAddress,
   225  			redistributionContractABI,
   226  			false,
   227  		)
   228  
   229  		_, err = contract.Claim(ctx, proofs)
   230  		if err != nil {
   231  			t.Fatal(err)
   232  		}
   233  	})
   234  
   235  	t.Run("Claim with tx reverted", func(t *testing.T) {
   236  		t.Parallel()
   237  
   238  		proofs := randChunkInclusionProofs(t)
   239  		expectedCallData, err := redistributionContractABI.Pack("claim", proofs.A, proofs.B, proofs.C)
   240  		if err != nil {
   241  			t.Fatal(err)
   242  		}
   243  		contract := redistribution.New(
   244  			overlay,
   245  			owner,
   246  			log.Noop,
   247  			transactionMock.New(
   248  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   249  					if *request.To == redistributionContractAddress {
   250  						if !bytes.Equal(expectedCallData[:32], request.Data[:32]) {
   251  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   252  						}
   253  						return txHashDeposited, nil
   254  					}
   255  					return common.Hash{}, errors.New("sent to wrong contract")
   256  				}),
   257  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   258  					if txHash == txHashDeposited {
   259  						return &types.Receipt{
   260  							Status: 0,
   261  						}, nil
   262  					}
   263  					return nil, errors.New("unknown tx hash")
   264  				}),
   265  			),
   266  			redistributionContractAddress,
   267  			redistributionContractABI,
   268  			false,
   269  		)
   270  
   271  		_, err = contract.Claim(ctx, proofs)
   272  		if !errors.Is(err, transaction.ErrTransactionReverted) {
   273  			t.Fatal(err)
   274  		}
   275  	})
   276  
   277  	t.Run("Commit", func(t *testing.T) {
   278  		t.Parallel()
   279  		var obfus [32]byte
   280  		testobfus := common.Hex2Bytes("hash")
   281  		copy(obfus[:], testobfus)
   282  		expectedCallData, err := redistributionContractABI.Pack("commit", obfus, uint64(0))
   283  		if err != nil {
   284  			t.Fatal(err)
   285  		}
   286  		contract := redistribution.New(
   287  			overlay,
   288  			owner,
   289  			log.Noop,
   290  			transactionMock.New(
   291  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   292  					if *request.To == redistributionContractAddress {
   293  						if !bytes.Equal(expectedCallData[:32], request.Data[:32]) {
   294  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   295  						}
   296  						return txHashDeposited, nil
   297  					}
   298  					return common.Hash{}, errors.New("sent to wrong contract")
   299  				}),
   300  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   301  					if txHash == txHashDeposited {
   302  						return &types.Receipt{
   303  							Status: 1,
   304  						}, nil
   305  					}
   306  					return nil, errors.New("unknown tx hash")
   307  				}),
   308  			),
   309  			redistributionContractAddress,
   310  			redistributionContractABI,
   311  			false,
   312  		)
   313  
   314  		_, err = contract.Commit(ctx, testobfus, 0)
   315  		if err != nil {
   316  			t.Fatal(err)
   317  		}
   318  	})
   319  
   320  	t.Run("Reveal", func(t *testing.T) {
   321  		t.Parallel()
   322  
   323  		reserveCommitmentHash := common.BytesToHash(common.Hex2Bytes("hash"))
   324  		randomNonce := common.BytesToHash(common.Hex2Bytes("nonce"))
   325  		depth := uint8(10)
   326  
   327  		expectedCallData, err := redistributionContractABI.Pack("reveal", depth, reserveCommitmentHash, randomNonce)
   328  		if err != nil {
   329  			t.Fatal(err)
   330  		}
   331  		contract := redistribution.New(
   332  			overlay,
   333  			owner,
   334  			log.Noop,
   335  			transactionMock.New(
   336  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, _ int) (txHash common.Hash, err error) {
   337  					if *request.To == redistributionContractAddress {
   338  						if !bytes.Equal(expectedCallData[:32], request.Data[:32]) {
   339  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   340  						}
   341  						return txHashDeposited, nil
   342  					}
   343  					return common.Hash{}, errors.New("sent to wrong contract")
   344  				}),
   345  				transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
   346  					if txHash == txHashDeposited {
   347  						return &types.Receipt{
   348  							Status: 1,
   349  						}, nil
   350  					}
   351  					return nil, errors.New("unknown tx hash")
   352  				}),
   353  			),
   354  			redistributionContractAddress,
   355  			redistributionContractABI,
   356  			false,
   357  		)
   358  
   359  		_, err = contract.Reveal(ctx, depth, common.Hex2Bytes("hash"), common.Hex2Bytes("nonce"))
   360  		if err != nil {
   361  			t.Fatal(err)
   362  		}
   363  	})
   364  
   365  	t.Run("Reserve Salt", func(t *testing.T) {
   366  		t.Parallel()
   367  		someSalt := testutil.RandBytes(t, 32)
   368  		contract := redistribution.New(
   369  			overlay,
   370  			owner,
   371  			log.Noop,
   372  			transactionMock.New(
   373  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   374  					if *request.To == redistributionContractAddress {
   375  
   376  						return someSalt, nil
   377  					}
   378  					return nil, errors.New("unexpected call")
   379  				}),
   380  			),
   381  			redistributionContractAddress,
   382  			redistributionContractABI,
   383  			false,
   384  		)
   385  
   386  		salt, err := contract.ReserveSalt(ctx)
   387  		if err != nil {
   388  			t.Fatal(err)
   389  		}
   390  		if !bytes.Equal(salt, someSalt) {
   391  			t.Fatal("expected bytes to be equal")
   392  		}
   393  	})
   394  
   395  	t.Run("send tx failed", func(t *testing.T) {
   396  		t.Parallel()
   397  
   398  		depth := uint8(10)
   399  		contract := redistribution.New(
   400  			overlay,
   401  			owner,
   402  			log.Noop,
   403  			transactionMock.New(
   404  				transactionMock.WithCallFunc(func(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) {
   405  					if *request.To == redistributionContractAddress {
   406  						return nil, errors.New("some error")
   407  					}
   408  					return nil, errors.New("unexpected call")
   409  				}),
   410  			),
   411  			redistributionContractAddress,
   412  			redistributionContractABI,
   413  			false,
   414  		)
   415  
   416  		_, err := contract.IsPlaying(ctx, depth)
   417  		if err == nil {
   418  			t.Fatal("expecting error")
   419  		}
   420  	})
   421  
   422  	t.Run("invalid call data", func(t *testing.T) {
   423  		t.Parallel()
   424  
   425  		expectedCallData, err := redistributionContractABI.Pack("commit", common.BytesToHash(common.Hex2Bytes("some hash")), uint64(0))
   426  		if err != nil {
   427  			t.Fatal(err)
   428  		}
   429  		contract := redistribution.New(
   430  			overlay,
   431  			owner,
   432  			log.Noop,
   433  			transactionMock.New(
   434  				transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
   435  					if *request.To == redistributionContractAddress {
   436  						if !bytes.Equal(expectedCallData[:], request.Data[:]) {
   437  							return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
   438  						}
   439  						return txHashDeposited, nil
   440  					}
   441  					return common.Hash{}, errors.New("sent to wrong contract")
   442  				}),
   443  			),
   444  			redistributionContractAddress,
   445  			redistributionContractABI,
   446  			false,
   447  		)
   448  
   449  		_, err = contract.Commit(ctx, common.Hex2Bytes("hash"), 0)
   450  		if err == nil {
   451  			t.Fatal("expected error")
   452  		}
   453  	})
   454  }