Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Downloaders for historical transfers #1473

Merged
merged 36 commits into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a0ef54e
Implement downloaders for historical transfers
dshulyak May 29, 2019
e214a73
Store only hash and number of the block
dshulyak May 30, 2019
ff3355f
Implement iterative downloader
dshulyak May 30, 2019
557be6e
Add tests that ensures that historical transfers will be included
dshulyak May 30, 2019
654f1bf
Send history event and update REDME
dshulyak May 30, 2019
84fea8b
Add more logs and adjust timeout after debuggin on main chain
dshulyak May 31, 2019
f671872
Use TransactionByHash instead of TransactionInBlock
dshulyak Jun 1, 2019
5e384d2
Adjust timeouts for erc20 downloader
dshulyak Jun 1, 2019
ec95d81
Transaction received in block can be nil
dshulyak Jun 1, 2019
6a67f43
Fix expectation in e2e test
dshulyak Jun 1, 2019
a383e85
Check transaction.To after signer
dshulyak Jun 1, 2019
1fb7fc2
Raise waiting interval if there was an error in any loop
dshulyak Jun 1, 2019
8f5e869
Accept hex encoding in API and handle not specified start value
dshulyak Jun 2, 2019
45fbd2e
Apply several suggestions after review
dshulyak Jun 3, 2019
bdf72b0
Implement faster downloader for historical eth transfers
dshulyak May 31, 2019
7162816
Test binary iterative downloader
dshulyak Jun 3, 2019
f803c40
Remove unused ethbatchSize
dshulyak Jun 3, 2019
fa3974d
Use parent ctx in iterators and hash of tx as a unique identifier
dshulyak Jun 3, 2019
7d66a23
Replace binary iterative downloader with concurrent downloader for eth
dshulyak Jun 4, 2019
f970755
Refactor logic from reactor
dshulyak Jun 4, 2019
38049c0
Rework downloaders so that can accept multiple accounts
dshulyak Jun 4, 2019
4fc000e
Support for downloading transfers for multiple accounts
dshulyak Jun 5, 2019
7a7ec16
Update readme with minor fixes
dshulyak Jun 5, 2019
f77ff62
Refactor issues reported by linter
dshulyak Jun 6, 2019
3a2a6f5
Rewrite concurrent downloader and make erc20 downloader concurrent
dshulyak Jun 6, 2019
cf0660b
Generate unique ID for every transfer
dshulyak Jun 6, 2019
742750a
Write better tests for reorg handling and improve handling description
dshulyak Jun 7, 2019
6750b7c
Renaming leftover
dshulyak Jun 7, 2019
9c5b3c8
Add logs and simplify lastKnownHeader
dshulyak Jun 7, 2019
f612b46
Update accounts with all blocks in the set
dshulyak Jun 7, 2019
e8adb6b
Encrypt database with same password taht is used for pfs db
dshulyak Jun 7, 2019
3e59c07
Rename ConcurrentRunner to AtomicGroup
dshulyak Jun 10, 2019
27021ac
Add fast catchup after app was offline for longer than 15 blocks
dshulyak Jun 10, 2019
860e69c
Remove ununes isSequence
dshulyak Jun 10, 2019
faf9525
Increase timeout in test: bootstrap procedure may take longer now
dshulyak Jun 10, 2019
4f02424
Remove unused code in database and adjust documentation
dshulyak Jun 11, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions api/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ func (b *StatusBackend) reSelectAccount() error {
default:
return err
}
return b.startWallet()
return nil
}

// SelectAccount selects current wallet and chat accounts, by verifying that each address has corresponding account which can be decrypted
Expand Down Expand Up @@ -551,10 +551,10 @@ func (b *StatusBackend) SelectAccount(walletAddress, chatAddress, password strin
return err
}
}
return b.startWallet()
return b.startWallet(password)
}

func (b *StatusBackend) startWallet() error {
func (b *StatusBackend) startWallet(password string) error {
if !b.statusNode.Config().WalletConfig.Enabled {
return nil
}
Expand All @@ -567,9 +567,9 @@ func (b *StatusBackend) startWallet() error {
return err
}
path := path.Join(b.statusNode.Config().DataDir, fmt.Sprintf("wallet-%x.sql", account.Address))
return wallet.StartReactor(path,
return wallet.StartReactor(path, password,
b.statusNode.RPCClient().Ethclient(),
account.Address,
[]common.Address{account.Address},
new(big.Int).SetUint64(b.statusNode.Config().NetworkID))
}

Expand Down
160 changes: 118 additions & 42 deletions services/wallet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ Returns avaiable transfers in a given range.
- `start`: `BIGINT` - start of the range
- `end`: `BIGINT` - end of the range. if nil query will return all transfers from start.

##### Examples

```json
{"jsonrpc":"2.0","id":14,"method":"wallet_getTransfers","params":[0,20]}
{"jsonrpc":"2.0","id":14,"method":"wallet_getTransfers","params":[0,null]}
{"jsonrpc":"2.0","id":13,"method":"wallet_getTransfers","params":[0]}
```

##### Returns

List of objects like:
Expand All @@ -42,55 +50,116 @@ List of objects like:
```json
[
{
"Type": "eth",
"Header": {
"parentHash": "0xd2130443688b760cb6710a8550ffe68106238a3103bf6e62f0784c9cb3e18591",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"miner": "0x0000000000000000000000000000000000000000",
"stateRoot": "0x420b2a421e99c28c3c07825c1ddac37e84cb55561b01c3702eb36a733499defe",
"transactionsRoot": "0x00a1aaef3eac0928cd2ecd7c00a4562e5db92cf4763db9840ba449904616a2c8",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x2",
"number": "0x1",
"gasLimit": "0x5ff7a7",
"gasUsed": "0x5208",
"timestamp": "0x5cebc0ed",
"extraData": "0xd883010817846765746888676f312e31322e35856c696e75780000000000000064b57fc2cdf3d0318f02602a90160b749dd2813908a58d6428e695d438e749fc71f7528bee286fe8827db3bb3fccb1aa76593e81c4d9d5f1f7387f61f8b2854000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000",
"hash": "0x576123ac3d561b618d2c9730e5c4432af8d18ed151caeac8b166757ea3b060c7"
"type": "erc20",
"address": "0x5dc6108dc6296b052bbd33000553afe0ea576b5e",
"blockNumber": 5687981,
"blockhash": "0xcc4553f125be0bc6cc974518368145fcf1344f41e5de238205db0a1c185ea2fc",
"transaction": {
"nonce": "0x57",
"gasPrice": "0x3b9aca00",
"gas": "0x44ba8",
"to": "0xc55cf4b03948d7ebc8b9e8bad92643703811d162",
"value": "0x0",
"input": "0xcae9ca5100000000000000000000000039d16cdb56b5a6a89e1a397a13fe48034694316e0000000000000000000000000000000000000000000000015af1d78b58c40000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000449134709e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000005dc6108dc6296b052bbd33000553afe0ea576b5e00000000000000000000000000000000000000000000000000000000",
"v": "0x29",
"r": "0x124587e9c1d16d8bd02fda1221aefbfca8e2f4cd6300ed2077ebf736789179ab",
"s": "0x4309fddc1226dacb877488221a439c4f97d77dc2c3f5c8ea51f34f42417d3bda",
"hash": "0x259dd45c9c4d52137f32b7787e6e1fb6c9faf70ba40b8137bf66ba03abc0da00"
},
"Transaction": {
"nonce": "0x0",
"gasPrice": "0xa",
"gas": "0xf4240",
"to": "0x72058a9d5a8194078ed372b34fa1fb8b8e5b7720",
"value": "0xde0b6b3a7640000",
"input": "0x",
"v": "0xa95",
"r": "0xd171c582139765f44fa1401edcdd377ca1b350ee10c0685073a5d470fc3625c6",
"s": "0x3392d24da2a13449345fbe8210d5af89f01ee21b456dc3c226e7cd7a0509fed",
"hash": "0x56be9c3cf40243e62428a203e37ce2104cfa12bef7d9e47988fd769617d361c6"
},
"Receipt": {
"receipt": {
"root": "0x",
"status": "0x1",
"cumulativeGasUsed": "0x5208",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"logs": [],
"transactionHash": "0x56be9c3cf40243e62428a203e37ce2104cfa12bef7d9e47988fd769617d361c6",
"cumulativeGasUsed": "0x389e1e",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000200000000020000000000000000000000000000000000004000000000000000200000000000000020000000000008000000000000000000000000000000000000000000000000020000000000002000000800000000100000000000000010000000000000000000400000000000000001000000000040000000400000000400000000020000000000000008000000000020000000010000000002000000000000020000000002000000000000000000000000000000000200000000000000000020000010000000000000000000000400000000000000000000000000000000000000",
"logs": [
{
"address": "0xc55cf4b03948d7ebc8b9e8bad92643703811d162",
"topics": [
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
"0x0000000000000000000000005dc6108dc6296b052bbd33000553afe0ea576b5e",
"0x00000000000000000000000039d16cdb56b5a6a89e1a397a13fe48034694316e"
],
"data": "0x0000000000000000000000000000000000000000000000015af1d78b58c40000",
"blockNumber": "0x56caad",
"transactionHash": "0x259dd45c9c4d52137f32b7787e6e1fb6c9faf70ba40b8137bf66ba03abc0da00",
"transactionIndex": "0x10",
"blockHash": "0xcc4553f125be0bc6cc974518368145fcf1344f41e5de238205db0a1c185ea2fc",
"logIndex": "0xd",
"removed": false
},
{
"address": "0xc55cf4b03948d7ebc8b9e8bad92643703811d162",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x0000000000000000000000005dc6108dc6296b052bbd33000553afe0ea576b5e",
"0x000000000000000000000000ee55b1661fd24c4760d92026cedb252a5a0f2a4e"
],
"data": "0x0000000000000000000000000000000000000000000000015af1d78b58c40000",
"blockNumber": "0x56caad",
"transactionHash": "0x259dd45c9c4d52137f32b7787e6e1fb6c9faf70ba40b8137bf66ba03abc0da00",
"transactionIndex": "0x10",
"blockHash": "0xcc4553f125be0bc6cc974518368145fcf1344f41e5de238205db0a1c185ea2fc",
"logIndex": "0xe",
"removed": false
},
{
"address": "0x39d16cdb56b5a6a89e1a397a13fe48034694316e",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000005dc6108dc6296b052bbd33000553afe0ea576b5e",
"0x0000000000000000000000000000000000000000000000000000000000000044"
],
"data": "0x",
"blockNumber": "0x56caad",
"transactionHash": "0x259dd45c9c4d52137f32b7787e6e1fb6c9faf70ba40b8137bf66ba03abc0da00",
"transactionIndex": "0x10",
"blockHash": "0xcc4553f125be0bc6cc974518368145fcf1344f41e5de238205db0a1c185ea2fc",
"logIndex": "0xf",
"removed": false
}
],
"transactionHash": "0x259dd45c9c4d52137f32b7787e6e1fb6c9faf70ba40b8137bf66ba03abc0da00",
"contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x5208"
"gasUsed": "0x34f42"
}
}
]
```

##### Examples

```json
{"jsonrpc":"2.0","id":14,"method":"wallet_getTransfers","params":[0,20]}
{"jsonrpc":"2.0","id":14,"method":"wallet_getTransfers","params":[0,null]}
{"jsonrpc":"2.0","id":13,"method":"wallet_getTransfers","params":[0]}
```

#### wallet_getTransfersByAddress

Returns avaiable transfers in a given range.

##### Parameters

- `address`: `HEX` - ethereum address encoded in hex
- `start`: `BIGINT` - start of the range
- `end`: `BIGINT` - end of the range. if nil query will return all transfers from start.

##### Examples

```json
{"jsonrpc":"2.0","id":7,"method":"wallet_getTransfersByAddress","params":["0xb81a6845649fa8c042dfaceb3f7a684873406993","0x0"]}
```

##### Returns

Objects in the same format.


Signals
-------

Two signals will are emitted:
Two signals can be emitted:

1. `newblock` signal

Expand All @@ -101,8 +170,12 @@ Client expected to request transfers starting from received block.
{
"type": "wallet",
"event": {
"Type": "newblock",
"BlockNumber": 10
"type": "newblock",
"blockNumber": 0,
"accounts": [
"0x42c8f505b4006d417dd4e0ba0e880692986adbd8",
"0x3129mdasmeo132128391fml1130410k312312mll"
]
}
}
```
Expand All @@ -116,8 +189,11 @@ Client expected to request new transfers from received block and replace transfe
{
"type": "wallet",
"event": {
"Type": "reorg",
"BlockNumber": 10
"type": "reorg",
"blockNumber": 0,
"accounts": [
"0x42c8f505b4006d417dd4e0ba0e880692986adbd8"
]
}
}
```
```
30 changes: 28 additions & 2 deletions services/wallet/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ import (
"errors"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
)

func NewAPI(s *Service) *API {
return &API{s}
}

// API is class with methods available over RPC.
type API struct {
s *Service
Expand All @@ -16,15 +22,35 @@ type API struct {
// GetTransfers returns transfers in range of blocks. If `end` is nil all transfers from `start` will be returned.
// TODO(dshulyak) benchmark loading many transfers from database. We can avoid json unmarshal/marshal if we will
// read header, tx and receipt as a raw json.
func (api *API) GetTransfers(ctx context.Context, start, end *big.Int) ([]Transfer, error) {
func (api *API) GetTransfers(ctx context.Context, start, end *hexutil.Big) ([]Transfer, error) {
log.Debug("call to get transfers", "start", start, "end", end)
if start == nil {
return nil, errors.New("start of the query must be provided. use 0 if you want to load all transfers")
}
if api.s.db == nil {
return nil, errors.New("wallet service is not initialized")
}
rst, err := api.s.db.GetTransfers(start, end)
rst, err := api.s.db.GetTransfers((*big.Int)(start), (*big.Int)(end))
if err != nil {
return nil, err
}
log.Debug("result from database for transfers", "start", start, "end", end, "len", len(rst))
return rst, nil
}

// GetTransfersByAddress returns transfers for a single address between two blocks.
func (api *API) GetTransfersByAddress(ctx context.Context, address common.Address, start, end *hexutil.Big) ([]Transfer, error) {
log.Debug("call to get transfers for an address", "address", address, "start", start, "end", end)
if start == nil {
return nil, errors.New("start of the query must be provided. use 0 if you want to load all transfers")
}
if api.s.db == nil {
return nil, errors.New("wallet service is not initialized")
}
rst, err := api.s.db.GetTransfersByAddress(address, (*big.Int)(start), (*big.Int)(end))
if err != nil {
return nil, err
}
log.Debug("result from database for address", "address", address, "start", start, "end", end, "len", len(rst))
return rst, nil
}
Loading