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 }