Match transfer to every account that is being watched

This commit is contained in:
dmitry 2019-08-27 12:16:09 +03:00 committed by Dmitry Shulyak
parent 0165b028c9
commit 7454586889
2 changed files with 63 additions and 49 deletions

View File

@ -101,36 +101,32 @@ func (d *ETHTransferDownloader) GetTransfersByNumber(ctx context.Context, number
func (d *ETHTransferDownloader) getTransfersInBlock(ctx context.Context, blk *types.Block, accounts []common.Address) (rst []Transfer, err error) { func (d *ETHTransferDownloader) getTransfersInBlock(ctx context.Context, blk *types.Block, accounts []common.Address) (rst []Transfer, err error) {
for _, tx := range blk.Transactions() { for _, tx := range blk.Transactions() {
var address *common.Address for _, address := range accounts {
from, err := types.Sender(d.signer, tx) from, err := types.Sender(d.signer, tx)
if err != nil {
return nil, err
}
if any(from, accounts) {
address = &from
} else if tx.To() != nil && any(*tx.To(), accounts) {
address = tx.To()
}
if address != nil {
receipt, err := d.client.TransactionReceipt(ctx, tx.Hash())
if err != nil { if err != nil {
return nil, err return nil, err
} }
if isTokenTransfer(receipt.Logs) { if from == address || (tx.To() != nil && *tx.To() == address) {
log.Debug("eth downloader found token transfer", "hash", tx.Hash()) receipt, err := d.client.TransactionReceipt(ctx, tx.Hash())
continue if err != nil {
} return nil, err
rst = append(rst, Transfer{ }
Type: ethTransfer, if isTokenTransfer(receipt.Logs) {
ID: tx.Hash(), log.Debug("eth downloader found token transfer", "hash", tx.Hash())
Address: *address, continue
BlockNumber: blk.Number(), }
BlockHash: blk.Hash(), rst = append(rst, Transfer{
Timestamp: blk.Time(), Type: ethTransfer,
Transaction: tx, ID: tx.Hash(),
From: from, Address: address,
Receipt: receipt}) BlockNumber: blk.Number(),
BlockHash: blk.Hash(),
Timestamp: blk.Time(),
Transaction: tx,
From: from,
Receipt: receipt})
}
} }
} }
// TODO(dshulyak) test that balance difference was covered by transactions // TODO(dshulyak) test that balance difference was covered by transactions
@ -311,15 +307,6 @@ func (d *ERC20TransfersDownloader) GetTransfersInRange(parent context.Context, f
return transfers, nil return transfers, nil
} }
func any(address common.Address, compare []common.Address) bool {
for _, c := range compare {
if c == address {
return true
}
}
return false
}
func isTokenTransfer(logs []*types.Log) bool { func isTokenTransfer(logs []*types.Log) bool {
signature := crypto.Keccak256Hash([]byte(erc20TransferEventSignature)) signature := crypto.Keccak256Hash([]byte(erc20TransferEventSignature))
for _, l := range logs { for _, l := range logs {

View File

@ -24,10 +24,10 @@ func TestETHTransfers(t *testing.T) {
type ETHTransferSuite struct { type ETHTransferSuite struct {
suite.Suite suite.Suite
ethclient *ethclient.Client ethclient *ethclient.Client
identity *ecdsa.PrivateKey identity, secondary *ecdsa.PrivateKey
faucet *ecdsa.PrivateKey faucet *ecdsa.PrivateKey
signer types.Signer signer types.Signer
downloader *ETHTransferDownloader downloader *ETHTransferDownloader
} }
@ -38,6 +38,8 @@ func (s *ETHTransferSuite) SetupTest() {
s.Require().NoError(err) s.Require().NoError(err)
s.faucet, err = crypto.GenerateKey() s.faucet, err = crypto.GenerateKey()
s.Require().NoError(err) s.Require().NoError(err)
s.secondary, err = crypto.GenerateKey()
s.Require().NoError(err)
node, err := miner.NewDevNode(crypto.PubkeyToAddress(s.faucet.PublicKey)) node, err := miner.NewDevNode(crypto.PubkeyToAddress(s.faucet.PublicKey))
s.Require().NoError(err) s.Require().NoError(err)
@ -48,22 +50,33 @@ func (s *ETHTransferSuite) SetupTest() {
s.ethclient = ethclient.NewClient(client) s.ethclient = ethclient.NewClient(client)
s.signer = types.NewEIP155Signer(big.NewInt(1337)) s.signer = types.NewEIP155Signer(big.NewInt(1337))
s.downloader = &ETHTransferDownloader{ s.downloader = &ETHTransferDownloader{
signer: s.signer, signer: s.signer,
client: s.ethclient, client: s.ethclient,
accounts: []common.Address{crypto.PubkeyToAddress(s.identity.PublicKey)}, accounts: []common.Address{
crypto.PubkeyToAddress(s.identity.PublicKey),
crypto.PubkeyToAddress(s.secondary.PublicKey)},
} }
} }
// signAndMineTx signs transaction with provided key and waits for it to be mined.
// uses configured faucet key if pkey is nil.
func (s *ETHTransferSuite) signAndMineTx(tx *types.Transaction, pkey *ecdsa.PrivateKey) {
if pkey == nil {
pkey = s.faucet
}
tx, err := types.SignTx(tx, s.signer, pkey)
s.Require().NoError(err)
s.Require().NoError(s.ethclient.SendTransaction(context.Background(), tx))
timeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err = bind.WaitMined(timeout, s.ethclient, tx)
s.Require().NoError(err)
}
func (s *ETHTransferSuite) TestNoBalance() { func (s *ETHTransferSuite) TestNoBalance() {
ctx := context.TODO() ctx := context.TODO()
tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1e18), 1e6, big.NewInt(10), nil) tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1e18), 1e6, big.NewInt(10), nil)
tx, err := types.SignTx(tx, s.signer, s.faucet) s.signAndMineTx(tx, nil)
s.Require().NoError(err)
s.Require().NoError(s.ethclient.SendTransaction(ctx, tx))
timeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err = bind.WaitMined(timeout, s.ethclient, tx)
s.Require().NoError(err)
header, err := s.ethclient.HeaderByNumber(ctx, nil) header, err := s.ethclient.HeaderByNumber(ctx, nil)
s.Require().NoError(err) s.Require().NoError(err)
@ -119,6 +132,20 @@ func (s *ETHTransferSuite) TestBalanceUpdatedOnOutbound() {
s.Require().Len(transfers, 1) s.Require().Len(transfers, 1)
} }
func (s *ETHTransferSuite) TestMultipleReferences() {
tx := types.NewTransaction(0, crypto.PubkeyToAddress(s.identity.PublicKey), big.NewInt(1e18), 1e6, big.NewInt(10), nil)
s.signAndMineTx(tx, nil)
tx = types.NewTransaction(0, crypto.PubkeyToAddress(s.secondary.PublicKey), big.NewInt(1e17), 1e6, big.NewInt(10), nil)
s.signAndMineTx(tx, s.identity)
header, err := s.ethclient.HeaderByNumber(context.Background(), nil)
s.Require().NoError(err)
s.Require().Equal(big.NewInt(2), header.Number)
transfers, err := s.downloader.GetTransfers(context.Background(), toDBHeader(header))
s.Require().NoError(err)
s.Require().Len(transfers, 2)
}
func TestERC20Transfers(t *testing.T) { func TestERC20Transfers(t *testing.T) {
suite.Run(t, new(ERC20TransferSuite)) suite.Run(t, new(ERC20TransferSuite))
} }