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

New Feature: Application Boxes in Indexer #1168

Merged
merged 56 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
4d86e74
New Feature: Indexer Application Box Ingestion (#1067)
tzaffi Aug 9, 2022
5681adb
Update go-algorand submodule (Remove “contact us” from box name misma…
Aug 9, 2022
ec18e29
Merge branch 'develop' into integration/boxes
Aug 9, 2022
7aa7f2f
errant extra comma in comment
tzaffi Aug 10, 2022
06ec61a
re-point submodule to lateast feature/avm-box commit
Aug 22, 2022
89283d7
Merge branch 'develop' into integration/boxes
Aug 22, 2022
9303c83
expose max_s3_keys haystack size in firstFromS3's needle search and t…
Aug 22, 2022
3570a16
Revert "expose max_s3_keys haystack size in firstFromS3's needle sear…
Aug 22, 2022
2e2b504
point to a newer box inclusive tar ball
Aug 23, 2022
ab0208c
Merge branch 'develop' into integration/boxes
Aug 23, 2022
cd08d66
Merge branch 'develop' into integration/boxes
Sep 1, 2022
e63df7d
update go-algorand submodule to feature/avm-box latest
Sep 2, 2022
f70ed58
update go.mod/sum to adjust for breakout of avm-abi from go-algorand
Sep 2, 2022
ae841ae
Merge branch 'develop' into integration/boxes
Sep 8, 2022
a759ca5
temporary: point to E2E test tarball to containing boxes
Sep 8, 2022
be68a93
update submodule
Sep 13, 2022
1a8b465
update submodule
Sep 13, 2022
5f199ed
Merge branch 'develop' of github.com:algorand/indexer into develop
Sep 14, 2022
4881e51
Merge branch 'develop' into integration/boxes
Sep 14, 2022
4bdc0a0
update submodule
Sep 14, 2022
d98ae7e
Change *string to ledgercore.ValueDelta{Data:} in kvmods (#1224)
tzaffi Sep 14, 2022
64a6462
New Feature: Lookup Boxes by app-id + Name and Search Boxes by app-id…
tzaffi Sep 14, 2022
32df6f8
Go Embed the TEAL Program (#1227)
tzaffi Sep 15, 2022
e58ccd3
update submodule
Sep 16, 2022
2864669
Merge remote-tracking branch 'refs/remotes/origin/integration/boxes' …
Sep 16, 2022
0443366
Update idb/postgres/postgres_boxes_test.go
tzaffi Sep 16, 2022
4dba1aa
Update api/handlers. Go
tzaffi Sep 16, 2022
da42502
per CR suggestion - amend fixtures test
Sep 16, 2022
0d5191b
per CR suggestion - remove ineffective assertion
Sep 16, 2022
ea4fc7a
response to CR comments - simplify SQL hardcodeing to ASC
Sep 16, 2022
35e87fa
fix inaccurate comment
Sep 16, 2022
4affdb1
Don't 404 on Boxes Search when there's No App (#1239)
tzaffi Sep 23, 2022
260786f
Fix inaccurate BoxesResponse next-token documentation (#1240)
jasonpaulos Sep 23, 2022
37f4120
Merge branch 'develop' into integration/boxes
Oct 3, 2022
62e41a8
merge and re-generate
Oct 3, 2022
a47ce18
Merge remote-tracking branch 'refs/remotes/origin/integration/boxes' …
Oct 3, 2022
c065e1e
regenerate
Oct 3, 2022
5d5fc5b
update submodule
Oct 3, 2022
193dbc8
Merge branch 'develop' into integration/boxes
Oct 5, 2022
1eae85f
latest go-algorand
Oct 11, 2022
bba69ef
Merge branch 'develop' into integration/boxes
Oct 11, 2022
b72192f
point to latest e2e tarball with boxes
Oct 11, 2022
c65dd10
Merge branch 'develop' into integration/boxes
Oct 26, 2022
239e6d6
latest go-algorand
Oct 26, 2022
ed83375
following go-algorand changes: KvValueDelta and []byte instead of Val…
Oct 26, 2022
9d93edc
test updates
Oct 27, 2022
3d4b6f0
update submodule
Oct 27, 2022
6deb9b3
latest tarball
Oct 28, 2022
7de386f
Update .circleci/config.yml
tzaffi Oct 31, 2022
8745cf3
update go-algorand latest from master
Nov 1, 2022
eddb0d0
pin E2E test to the last rel/nightly
Nov 1, 2022
bda577c
Merge remote-tracking branch 'refs/remotes/origin/integration/boxes' …
Nov 1, 2022
5d1a24c
update submodule with lint fix
Nov 1, 2022
21ac00c
go mod tidy for latest msgp
Nov 1, 2022
802bc02
once again that sneaky EOL
Nov 1, 2022
acec7c4
update go-algorand some more - including catchpoint fix
Nov 1, 2022
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
4 changes: 4 additions & 0 deletions idb/postgres/internal/encoding/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,8 @@ func convertTrimmedLcAccountData(ad ledgercore.AccountData) baseAccountData {
TotalAssets: ad.TotalAssets,
TotalAppParams: ad.TotalAppParams,
TotalAppLocalStates: ad.TotalAppLocalStates,
TotalBoxes: ad.TotalBoxes,
TotalBoxBytes: ad.TotalBoxBytes,
baseOnlineAccountData: baseOnlineAccountData{
VoteID: ad.VoteID,
SelectionID: ad.SelectionID,
Expand All @@ -711,6 +713,8 @@ func unconvertTrimmedLcAccountData(ba baseAccountData) ledgercore.AccountData {
TotalAppLocalStates: ba.TotalAppLocalStates,
TotalAssetParams: ba.TotalAssetParams,
TotalAssets: ba.TotalAssets,
TotalBoxes: ba.TotalBoxes,
TotalBoxBytes: ba.TotalBoxBytes,
},
VotingData: ledgercore.VotingData{
VoteID: ba.VoteID,
Expand Down
50 changes: 49 additions & 1 deletion idb/postgres/internal/encoding/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package encoding

import (
"math/rand"
"reflect"
"testing"

"github.com/algorand/go-algorand/crypto"
Expand Down Expand Up @@ -580,6 +581,8 @@ func TestLcAccountDataEncoding(t *testing.T) {
TotalAppLocalStates: 11,
TotalAssetParams: 12,
TotalAssets: 13,
TotalBoxes: 20,
TotalBoxBytes: 21,
},
VotingData: ledgercore.VotingData{
VoteID: voteID,
Expand All @@ -592,10 +595,55 @@ func TestLcAccountDataEncoding(t *testing.T) {
}
buf := EncodeTrimmedLcAccountData(ad)

expectedString := `{"onl":1,"sel":"DwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","spend":"BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","stprf":"EwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","tapl":11,"tapp":10,"tas":13,"tasp":12,"teap":9,"tsch":{"nbs":8,"nui":7},"vote":"DgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","voteFst":16,"voteKD":18,"voteLst":17}`
expectedString := `{"onl":1,"sel":"DwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","spend":"BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","stprf":"EwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","tapl":11,"tapp":10,"tas":13,"tasp":12,"tbx":20,"tbxb":21,"teap":9,"tsch":{"nbs":8,"nui":7},"vote":"DgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","voteFst":16,"voteKD":18,"voteLst":17}`
assert.Equal(t, expectedString, string(buf))

decodedAd, err := DecodeTrimmedLcAccountData(buf)
require.NoError(t, err)
assert.Equal(t, ad, decodedAd)
}

// structFields recursively gets all field names in a struct
func structFields(theStruct interface{}, skip map[string]bool, names map[string]bool) {
rStruct := reflect.TypeOf(theStruct)
numFields := rStruct.NumField()
for i := 0; i < numFields; i++ {
field := rStruct.Field(i)
name := field.Name
if totalSkip, nameSkip := skip[name]; nameSkip {
if totalSkip {
continue
}
} else {
names[name] = true
}
if field.Type.Kind() == reflect.Struct {
structFields(reflect.New(field.Type).Elem().Interface(), skip, names)
}
}
}

// Test that all fields in go-algorand's AccountBaseData are either in local baseAccountData
// or are accounted for explicitly in "skip"
func TestBaseAccountDataVersusAccountBaseDataParity(t *testing.T) {

skip := map[string]bool{
"_struct": true,
"MicroAlgos": true,
"RewardsBase": true,
"RewardedMicroAlgos": true,
"MicroAlgosWithRewards": true,
"VotingData": false, // skip the name, but continue with the recursion
}

goalNames := map[string]bool{}
structFields(ledgercore.AccountBaseData{}, skip, goalNames)
structFields(ledgercore.OnlineAccountData{}, skip, goalNames)

indexerNames := map[string]bool{}
structFields(baseAccountData{}, skip, indexerNames)

for name := range goalNames {
require.Contains(t, indexerNames, name)
}
}
2 changes: 2 additions & 0 deletions idb/postgres/internal/encoding/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ type baseAccountData struct {
TotalAssets uint64 `codec:"tas"`
TotalAppParams uint64 `codec:"tapp"`
TotalAppLocalStates uint64 `codec:"tapl"`
TotalBoxes uint64 `codec:"tbx"`
TotalBoxBytes uint64 `codec:"tbxb"`

baseOnlineAccountData
}
8 changes: 8 additions & 0 deletions idb/postgres/internal/schema/setup_postgres.sql
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,11 @@ CREATE TABLE IF NOT EXISTS account_app (

-- For looking up existing app local states by account
CREATE INDEX IF NOT EXISTS account_app_by_addr_partial ON account_app(addr) WHERE NOT deleted;

-- For looking up app box storage
CREATE TABLE IF NOT EXISTS app_box (
app bigint NOT NULL,
name bytea NOT NULL,
value bytea NOT NULL, -- upon creation 'value' is 0x000...000 with length being the box'es size
PRIMARY KEY (app, name)
);
8 changes: 8 additions & 0 deletions idb/postgres/internal/schema/setup_postgres_sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion idb/postgres/internal/writer/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
type copyFromChannelStruct struct {
ch chan []interface{}
next []interface{}
err error
}

func (c *copyFromChannelStruct) Next() bool {
Expand Down
43 changes: 40 additions & 3 deletions idb/postgres/internal/writer/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/jackc/pgx/v4"

Expand All @@ -32,6 +33,8 @@ const (
deleteAccountAssetStmtName = "delete_account_asset"
deleteAppStmtName = "delete_app"
deleteAccountAppStmtName = "delete_account_app"
upsertAppBoxStmtName = "upsert_app_box"
deleteAppBoxStmtName = "delete_app_box"
updateAccountTotalsStmtName = "update_account_totals"
)

Expand Down Expand Up @@ -104,6 +107,12 @@ var statements = map[string]string{
(addr, app, localstate, deleted, created_at, closed_at)
VALUES($1, $2, 'null'::jsonb, TRUE, $3, $3) ON CONFLICT (addr, app) DO UPDATE SET
localstate = EXCLUDED.localstate, deleted = TRUE, closed_at = EXCLUDED.closed_at`,
upsertAppBoxStmtName: `INSERT INTO app_box AS ab
(app, name, value)
VALUES ($1, $2, $3)
ON CONFLICT (app, name) DO UPDATE SET
value = EXCLUDED.value`,
deleteAppBoxStmtName: `DELETE FROM app_box WHERE app = $1 and name = $2`,
updateAccountTotalsStmtName: `UPDATE metastate SET v = $1 WHERE k = '` +
schema.AccountTotals + `'`,
}
Expand All @@ -122,7 +131,7 @@ func MakeWriter(tx pgx.Tx) (Writer, error) {
for name, query := range statements {
_, err := tx.Prepare(context.Background(), name, query)
if err != nil {
return Writer{}, fmt.Errorf("MakeWriter() prepare statement err: %w", err)
return Writer{}, fmt.Errorf("MakeWriter() prepare statement for name '%s' err: %w", name, err)
}
}

Expand Down Expand Up @@ -290,6 +299,28 @@ func writeAccountDeltas(round basics.Round, accountDeltas *ledgercore.AccountDel
writeAppResource(round, &appResources[i], batch)
}
}

}

func writeBoxMods(kvMods map[string]*string, batch *pgx.Batch) error {
// INSERT INTO / UPDATE / DELETE FROM `app_box`
// WARNING: kvMods can in theory support more general storage types than app boxes.
// However, here we assume that all the provided kvMods represent app boxes.
// If a non-box is encountered inside kvMods, an error will be returned and
// AddBlock() will fail with the import getting stuck at the corresponding round.
for key, value := range kvMods {
app, name, err := logic.SplitBoxKey(key)
if err != nil {
return fmt.Errorf("writeBoxMods() err: %w", err)
}
if value != nil {
batch.Queue(upsertAppBoxStmtName, app, []byte(name), []byte(*value))
} else {
batch.Queue(deleteAppBoxStmtName, app, []byte(name))
}
}

return nil
}

// AddBlock0 writes block 0 to the database.
Expand All @@ -309,12 +340,12 @@ func (w *Writer) AddBlock0(block *bookkeeping.Block) error {
_, err := results.Exec()
if err != nil {
results.Close()
return fmt.Errorf("AddBlock() exec err: %w", err)
return fmt.Errorf("AddBlock0() exec err: %w", err)
}
}
err := results.Close()
if err != nil {
return fmt.Errorf("AddBlock() close results err: %w", err)
return fmt.Errorf("AddBlock0() close results err: %w", err)
}

return nil
Expand All @@ -339,6 +370,12 @@ func (w *Writer) AddBlock(block *bookkeeping.Block, modifiedTxns []transactions.
}
writeAccountDeltas(block.Round(), &delta.Accts, sigTypeDeltas, &batch)
}
{
err := writeBoxMods(delta.KvMods, &batch)
if err != nil {
return fmt.Errorf("AddBlock() err on boxes: %w", err)
}
}
batch.Queue(updateAccountTotalsStmtName, encoding.EncodeAccountTotals(&delta.Totals))

results := w.tx.SendBatch(context.Background(), &batch)
Expand Down
Loading