Skip to content

Commit 129feb7

Browse files
Merge pull request #30 from coinbase/patrick/historical-balance-lookup
[services] Add historical balance lookup
2 parents ae2ff20 + e1d4547 commit 129feb7

19 files changed

+514
-68
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
rosetta-bitcoin
22
bitcoin-data
3+
cli-data

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.13
55
require (
66
github.com/btcsuite/btcd v0.21.0-beta
77
github.com/btcsuite/btcutil v1.0.2
8-
github.com/coinbase/rosetta-sdk-go v0.5.7
8+
github.com/coinbase/rosetta-sdk-go v0.5.8-0.20201027222031-dd9e29377d5f
99
github.com/dgraph-io/badger/v2 v2.2007.2
1010
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
1111
github.com/stretchr/testify v1.6.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJ
6161
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
6262
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
6363
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
64-
github.com/coinbase/rosetta-sdk-go v0.5.7 h1:BaR/+O3GzrsyunVNkVQHtjDCcId8G1Fh/RqEbeyExnk=
65-
github.com/coinbase/rosetta-sdk-go v0.5.7/go.mod h1:l5aNeyeZKBkmWbVdkdLpWdToQ6hTwI7cZ1OU9cMbljY=
64+
github.com/coinbase/rosetta-sdk-go v0.5.8-0.20201027222031-dd9e29377d5f h1:aWkN9dKMkMMpZKX5QycpePxH176Fj2fNNC7jESfLZw0=
65+
github.com/coinbase/rosetta-sdk-go v0.5.8-0.20201027222031-dd9e29377d5f/go.mod h1:l5aNeyeZKBkmWbVdkdLpWdToQ6hTwI7cZ1OU9cMbljY=
6666
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
6767
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
6868
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=

indexer/balance_storage_handler.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2020 Coinbase, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package indexer
16+
17+
import (
18+
"context"
19+
20+
"github.com/coinbase/rosetta-sdk-go/parser"
21+
"github.com/coinbase/rosetta-sdk-go/storage"
22+
"github.com/coinbase/rosetta-sdk-go/types"
23+
)
24+
25+
var _ storage.BalanceStorageHandler = (*BalanceStorageHandler)(nil)
26+
27+
// BalanceStorageHandler implements storage.BalanceStorageHandler.
28+
type BalanceStorageHandler struct{}
29+
30+
// BlockAdded is called whenever a block is committed to BlockStorage.
31+
func (h *BalanceStorageHandler) BlockAdded(
32+
ctx context.Context,
33+
block *types.Block,
34+
changes []*parser.BalanceChange,
35+
) error {
36+
return nil
37+
}
38+
39+
// BlockRemoved is called whenever a block is removed from BlockStorage.
40+
func (h *BalanceStorageHandler) BlockRemoved(
41+
ctx context.Context,
42+
block *types.Block,
43+
changes []*parser.BalanceChange,
44+
) error {
45+
return nil
46+
}

indexer/balance_storage_helper.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2020 Coinbase, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package indexer
16+
17+
import (
18+
"context"
19+
20+
"github.com/coinbase/rosetta-sdk-go/asserter"
21+
"github.com/coinbase/rosetta-sdk-go/parser"
22+
"github.com/coinbase/rosetta-sdk-go/storage"
23+
"github.com/coinbase/rosetta-sdk-go/types"
24+
)
25+
26+
var _ storage.BalanceStorageHelper = (*BalanceStorageHelper)(nil)
27+
28+
// BalanceStorageHelper implements storage.BalanceStorageHelper.
29+
type BalanceStorageHelper struct {
30+
a *asserter.Asserter
31+
}
32+
33+
// AccountBalance attempts to fetch the balance
34+
// for a missing account in storage.
35+
func (h *BalanceStorageHelper) AccountBalance(
36+
ctx context.Context,
37+
account *types.AccountIdentifier,
38+
currency *types.Currency,
39+
block *types.BlockIdentifier,
40+
) (*types.Amount, error) {
41+
return &types.Amount{
42+
Value: zeroValue,
43+
Currency: currency,
44+
}, nil
45+
}
46+
47+
// Asserter returns a *asserter.Asserter.
48+
func (h *BalanceStorageHelper) Asserter() *asserter.Asserter {
49+
return h.a
50+
}
51+
52+
// BalanceExemptions returns a list of *types.BalanceExemption.
53+
func (h *BalanceStorageHelper) BalanceExemptions() []*types.BalanceExemption {
54+
return []*types.BalanceExemption{}
55+
}
56+
57+
// ExemptFunc returns a parser.ExemptOperation.
58+
func (h *BalanceStorageHelper) ExemptFunc() parser.ExemptOperation {
59+
return func(op *types.Operation) bool {
60+
return false
61+
}
62+
}

indexer/coin_storage_helper.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2020 Coinbase, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package indexer
16+
17+
import (
18+
"context"
19+
20+
"github.com/coinbase/rosetta-sdk-go/storage"
21+
"github.com/coinbase/rosetta-sdk-go/types"
22+
)
23+
24+
var _ storage.CoinStorageHelper = (*CoinStorageHelper)(nil)
25+
26+
// CoinStorageHelper implements storage.CoinStorageHelper.
27+
type CoinStorageHelper struct {
28+
b *storage.BlockStorage
29+
}
30+
31+
// CurrentBlockIdentifier returns the current head block identifier
32+
// and is used to comply with the CoinStorageHelper interface.
33+
func (h *CoinStorageHelper) CurrentBlockIdentifier(
34+
ctx context.Context,
35+
transaction storage.DatabaseTransaction,
36+
) (*types.BlockIdentifier, error) {
37+
return h.b.GetHeadBlockIdentifierTransactional(ctx, transaction)
38+
}

indexer/indexer.go

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ const (
5353
// this is the estimated memory overhead for each
5454
// block fetched by the indexer.
5555
sizeMultiplier = 15
56+
57+
// zeroValue is 0 as a string
58+
zeroValue = "0"
5659
)
5760

5861
var (
@@ -74,7 +77,6 @@ type Client interface {
7477
var _ syncer.Handler = (*Indexer)(nil)
7578
var _ syncer.Helper = (*Indexer)(nil)
7679
var _ services.Indexer = (*Indexer)(nil)
77-
var _ storage.CoinStorageHelper = (*Indexer)(nil)
7880

7981
// Indexer caches blocks and provides balance query functionality.
8082
type Indexer struct {
@@ -85,11 +87,12 @@ type Indexer struct {
8587

8688
client Client
8789

88-
asserter *asserter.Asserter
89-
database storage.Database
90-
blockStorage *storage.BlockStorage
91-
coinStorage *storage.CoinStorage
92-
workers []storage.BlockWorker
90+
asserter *asserter.Asserter
91+
database storage.Database
92+
blockStorage *storage.BlockStorage
93+
balanceStorage *storage.BalanceStorage
94+
coinStorage *storage.CoinStorage
95+
workers []storage.BlockWorker
9396

9497
waiter *waitTable
9598
}
@@ -197,9 +200,21 @@ func Initialize(
197200
asserter: asserter,
198201
}
199202

200-
coinStorage := storage.NewCoinStorage(localStore, i, asserter)
203+
coinStorage := storage.NewCoinStorage(
204+
localStore,
205+
&CoinStorageHelper{blockStorage},
206+
asserter,
207+
)
201208
i.coinStorage = coinStorage
202-
i.workers = []storage.BlockWorker{coinStorage}
209+
210+
balanceStorage := storage.NewBalanceStorage(localStore)
211+
balanceStorage.Initialize(
212+
&BalanceStorageHelper{asserter},
213+
&BalanceStorageHandler{},
214+
)
215+
i.balanceStorage = balanceStorage
216+
217+
i.workers = []storage.BlockWorker{coinStorage, balanceStorage}
203218

204219
return i, nil
205220
}
@@ -748,7 +763,11 @@ func (i *Indexer) GetBlockTransaction(
748763
blockIdentifier *types.BlockIdentifier,
749764
transactionIdentifier *types.TransactionIdentifier,
750765
) (*types.Transaction, error) {
751-
return i.blockStorage.GetBlockTransaction(ctx, blockIdentifier, transactionIdentifier)
766+
return i.blockStorage.GetBlockTransaction(
767+
ctx,
768+
blockIdentifier,
769+
transactionIdentifier,
770+
)
752771
}
753772

754773
// GetCoins returns all unspent coins for a particular *types.AccountIdentifier.
@@ -759,11 +778,42 @@ func (i *Indexer) GetCoins(
759778
return i.coinStorage.GetCoins(ctx, accountIdentifier)
760779
}
761780

762-
// CurrentBlockIdentifier returns the current head block identifier
763-
// and is used to comply with the CoinStorageHelper interface.
764-
func (i *Indexer) CurrentBlockIdentifier(
781+
// GetBalance returns the balance of an account
782+
// at a particular *types.PartialBlockIdentifier.
783+
func (i *Indexer) GetBalance(
765784
ctx context.Context,
766-
transaction storage.DatabaseTransaction,
767-
) (*types.BlockIdentifier, error) {
768-
return i.blockStorage.GetHeadBlockIdentifierTransactional(ctx, transaction)
785+
accountIdentifier *types.AccountIdentifier,
786+
currency *types.Currency,
787+
blockIdentifier *types.PartialBlockIdentifier,
788+
) (*types.Amount, *types.BlockIdentifier, error) {
789+
dbTx := i.database.NewDatabaseTransaction(ctx, false)
790+
defer dbTx.Discard(ctx)
791+
792+
blockResponse, err := i.blockStorage.GetBlockLazyTransactional(
793+
ctx,
794+
blockIdentifier,
795+
dbTx,
796+
)
797+
if err != nil {
798+
return nil, nil, err
799+
}
800+
801+
amount, err := i.balanceStorage.GetBalanceTransactional(
802+
ctx,
803+
dbTx,
804+
accountIdentifier,
805+
currency,
806+
blockResponse.Block.BlockIdentifier.Index,
807+
)
808+
if errors.Is(err, storage.ErrAccountMissing) {
809+
return &types.Amount{
810+
Value: zeroValue,
811+
Currency: currency,
812+
}, blockResponse.Block.BlockIdentifier, nil
813+
}
814+
if err != nil {
815+
return nil, nil, err
816+
}
817+
818+
return amount, blockResponse.Block.BlockIdentifier, nil
769819
}

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ func main() {
154154
// requests.
155155
asserter, err := asserter.NewServer(
156156
bitcoin.OperationTypes,
157-
false,
157+
services.HistoricalBalanceLookup,
158158
[]*types.NetworkIdentifier{cfg.Network},
159159
nil,
160160
)

mocks/services/indexer.go

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rosetta-cli-conf/mainnet/config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
"http_timeout": 300,
88
"max_retries": 5,
99
"retry_elapsed_time": 0,
10-
"max_online_connections": 0,
10+
"max_online_connections": 1000,
1111
"max_sync_concurrency": 0,
1212
"tip_delay": 1800,
1313
"log_configuration": false,
14+
"compression_disabled": true,
15+
"memory_limit_disabled": true,
1416
"data": {
1517
"active_reconciliation_concurrency": 0,
1618
"inactive_reconciliation_concurrency": 0,

0 commit comments

Comments
 (0)