2019-06-14 10:16:30 +00:00
|
|
|
package wallet
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"math/big"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/core"
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
"github.com/ethereum/go-ethereum/event"
|
|
|
|
"github.com/status-im/status-go/t/devtests/testchain"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestNewBlocksSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(NewBlocksSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type NewBlocksSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
backend *testchain.Backend
|
|
|
|
cmd *newBlocksTransfersCommand
|
|
|
|
address common.Address
|
|
|
|
db *Database
|
|
|
|
dbStop func()
|
|
|
|
feed *event.Feed
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) SetupTest() {
|
|
|
|
var err error
|
|
|
|
db, stop := setupTestDB(s.Suite.T())
|
|
|
|
s.db = db
|
|
|
|
s.dbStop = stop
|
|
|
|
s.backend, err = testchain.NewBackend()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
account, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.address = crypto.PubkeyToAddress(account.PublicKey)
|
|
|
|
s.feed = &event.Feed{}
|
|
|
|
s.cmd = &newBlocksTransfersCommand{
|
|
|
|
db: s.db,
|
|
|
|
accounts: []common.Address{s.address},
|
2019-07-10 09:08:43 +00:00
|
|
|
erc20: NewERC20TransfersDownloader(s.backend.Client, []common.Address{s.address}, s.backend.Signer),
|
2019-06-14 10:16:30 +00:00
|
|
|
eth: ÐTransferDownloader{
|
|
|
|
client: s.backend.Client,
|
|
|
|
signer: s.backend.Signer,
|
|
|
|
accounts: []common.Address{s.address},
|
|
|
|
},
|
|
|
|
feed: s.feed,
|
|
|
|
client: s.backend.Client,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) TearDownTest() {
|
|
|
|
s.dbStop()
|
|
|
|
s.Require().NoError(s.backend.Stop())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) TestOneBlock() {
|
|
|
|
ctx := context.Background()
|
|
|
|
s.Require().EqualError(s.cmd.Run(ctx), "not found")
|
|
|
|
tx := types.NewTransaction(0, s.address, big.NewInt(1e17), 21000, big.NewInt(1), nil)
|
|
|
|
tx, err := types.SignTx(tx, s.backend.Signer, s.backend.Faucet)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
blocks := s.backend.GenerateBlocks(1, 0, func(n int, gen *core.BlockGen) {
|
|
|
|
gen.AddTx(tx)
|
|
|
|
})
|
|
|
|
n, err := s.backend.Ethereum.BlockChain().InsertChain(blocks)
|
|
|
|
s.Require().Equal(1, n)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
events := make(chan Event, 1)
|
|
|
|
sub := s.feed.Subscribe(events)
|
|
|
|
defer sub.Unsubscribe()
|
|
|
|
|
|
|
|
s.Require().NoError(s.cmd.Run(ctx))
|
|
|
|
|
|
|
|
select {
|
|
|
|
case ev := <-events:
|
|
|
|
s.Require().Equal(ev.Type, EventNewBlock)
|
|
|
|
s.Require().Equal(ev.BlockNumber, big.NewInt(1))
|
|
|
|
default:
|
|
|
|
s.Require().FailNow("event wasn't emitted")
|
|
|
|
}
|
|
|
|
transfers, err := s.db.GetTransfers(big.NewInt(0), nil)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(transfers, 1)
|
|
|
|
s.Require().Equal(tx.Hash(), transfers[0].ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) genTx(nonce int) *types.Transaction {
|
|
|
|
tx := types.NewTransaction(uint64(nonce), s.address, big.NewInt(1e10), 21000, big.NewInt(1), nil)
|
|
|
|
tx, err := types.SignTx(tx, s.backend.Signer, s.backend.Faucet)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
return tx
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) runCmdUntilError(ctx context.Context) (err error) {
|
|
|
|
for err == nil {
|
|
|
|
err = s.cmd.Run(ctx)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) TestReorg() {
|
|
|
|
blocks := s.backend.GenerateBlocks(20, 0, nil)
|
|
|
|
n, err := s.backend.Ethereum.BlockChain().InsertChain(blocks)
|
|
|
|
s.Require().Equal(20, n)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
s.Require().EqualError(s.runCmdUntilError(ctx), "not found")
|
|
|
|
|
|
|
|
blocks = s.backend.GenerateBlocks(3, 20, func(n int, gen *core.BlockGen) {
|
|
|
|
gen.AddTx(s.genTx(n))
|
|
|
|
})
|
|
|
|
n, err = s.backend.Ethereum.BlockChain().InsertChain(blocks)
|
|
|
|
s.Require().Equal(3, n)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// `not found` returned when we query head+1 block
|
|
|
|
ctx, cancel = context.WithTimeout(context.Background(), 3*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
s.cmd.from = toDBHeader(s.backend.Ethereum.BlockChain().GetHeaderByNumber(15))
|
|
|
|
s.Require().EqualError(s.runCmdUntilError(ctx), "not found")
|
|
|
|
|
|
|
|
transfers, err := s.db.GetTransfers(big.NewInt(0), nil)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(transfers, 3)
|
|
|
|
|
|
|
|
blocks = s.backend.GenerateBlocks(10, 15, func(n int, gen *core.BlockGen) {
|
|
|
|
gen.AddTx(s.genTx(n))
|
|
|
|
})
|
|
|
|
n, err = s.backend.Ethereum.BlockChain().InsertChain(blocks)
|
|
|
|
s.Require().Equal(10, n)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// it will be less but even if something went wrong we can't get more
|
|
|
|
events := make(chan Event, 10)
|
|
|
|
sub := s.feed.Subscribe(events)
|
|
|
|
defer sub.Unsubscribe()
|
|
|
|
|
|
|
|
ctx, cancel = context.WithTimeout(context.Background(), 3*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
s.Require().EqualError(s.runCmdUntilError(ctx), "not found")
|
|
|
|
|
|
|
|
close(events)
|
|
|
|
expected := []Event{{Type: EventReorg, BlockNumber: big.NewInt(16)}, {Type: EventNewBlock, BlockNumber: big.NewInt(25)}}
|
|
|
|
i := 0
|
|
|
|
for ev := range events {
|
|
|
|
s.Require().Equal(expected[i].Type, ev.Type)
|
|
|
|
s.Require().Equal(expected[i].BlockNumber, ev.BlockNumber)
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
transfers, err = s.db.GetTransfers(big.NewInt(0), nil)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(transfers, 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) downloadHistorical() {
|
|
|
|
blocks := s.backend.GenerateBlocks(40, 0, func(n int, gen *core.BlockGen) {
|
|
|
|
if n == 36 {
|
|
|
|
gen.AddTx(s.genTx(0))
|
|
|
|
} else if n == 39 {
|
|
|
|
gen.AddTx(s.genTx(1))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
n, err := s.backend.Ethereum.BlockChain().InsertChain(blocks)
|
|
|
|
s.Require().Equal(40, n)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
eth := ðHistoricalCommand{
|
|
|
|
db: s.db,
|
|
|
|
eth: ÐTransferDownloader{
|
|
|
|
client: s.backend.Client,
|
|
|
|
signer: s.backend.Signer,
|
|
|
|
accounts: []common.Address{s.address},
|
|
|
|
},
|
|
|
|
feed: s.feed,
|
|
|
|
address: s.address,
|
|
|
|
client: s.backend.Client,
|
|
|
|
to: s.backend.Ethereum.BlockChain().CurrentBlock().Number(),
|
|
|
|
}
|
|
|
|
s.Require().NoError(eth.Run(context.Background()), "eth historical command failed to sync transfers")
|
|
|
|
transfers, err := s.db.GetTransfers(big.NewInt(0), nil)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(transfers, 2)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) reorgHistorical() {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
s.Require().EqualError(s.runCmdUntilError(ctx), "not found")
|
|
|
|
|
|
|
|
blocks := s.backend.GenerateBlocks(10, 35, nil)
|
|
|
|
n, err := s.backend.Ethereum.BlockChain().InsertChain(blocks)
|
|
|
|
s.Require().Equal(10, n)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ctx, cancel = context.WithTimeout(context.Background(), 3*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
s.Require().EqualError(s.runCmdUntilError(ctx), "not found")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) TestSafetyBufferFailure() {
|
|
|
|
s.downloadHistorical()
|
|
|
|
|
|
|
|
s.reorgHistorical()
|
|
|
|
|
|
|
|
transfers, err := s.db.GetTransfers(big.NewInt(0), nil)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(transfers, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *NewBlocksSuite) TestSafetyBufferSuccess() {
|
|
|
|
s.downloadHistorical()
|
|
|
|
|
|
|
|
safety := new(big.Int).Sub(s.backend.Ethereum.BlockChain().CurrentHeader().Number, big.NewInt(10))
|
|
|
|
s.cmd.from = toDBHeader(s.backend.Ethereum.BlockChain().GetHeaderByNumber(safety.Uint64()))
|
|
|
|
s.reorgHistorical()
|
|
|
|
|
|
|
|
transfers, err := s.db.GetTransfers(big.NewInt(0), nil)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(transfers, 0)
|
|
|
|
}
|