Skip to content

Commit

Permalink
Use integer for root intra in TxnExtra (#763)
Browse files Browse the repository at this point in the history
* Use integer for root intra in TxnExtra.

* Update comment.
  • Loading branch information
tolikzinovyev authored Nov 3, 2021
1 parent 242e7eb commit ad96531
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 35 deletions.
11 changes: 4 additions & 7 deletions api/converter_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func stateDeltaToStateDelta(d basics.StateDelta) *generated.StateDelta {
type rowData struct {
Round uint64
RoundTime int64
Intra int
Intra uint
AssetID uint64
AssetCloseAmount uint64
}
Expand Down Expand Up @@ -270,16 +270,13 @@ func txnRowToTransaction(row idb.TxnRow) (generated.Transaction, error) {
extra := rowData{
Round: row.Round,
RoundTime: row.RoundTime.Unix(),
Intra: row.Intra,
Intra: uint(row.Intra),
AssetID: row.AssetID,
AssetCloseAmount: row.Extra.AssetCloseAmount,
}

if row.Extra.RootIntra != "" {
extra.Intra, err = strconv.Atoi(row.Extra.RootIntra)
if err != nil {
return generated.Transaction{}, fmt.Errorf("txnRowToTransaction(): failed to parse root-intra (%s): %w", row.Extra.RootIntra, err)
}
if row.Extra.RootIntra.Present {
extra.Intra = row.Extra.RootIntra.Value
}

txn, err := signedTxnWithAdToTransaction(&stxn, extra)
Expand Down
47 changes: 39 additions & 8 deletions idb/idb.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ type TxnRow struct {
Error error
}

func countInner(stxn *transactions.SignedTxnWithAD) int {
num := 0
func countInner(stxn *transactions.SignedTxnWithAD) uint {
num := uint(0)
for _, itxn := range stxn.ApplyData.EvalDelta.InnerTxns {
num++
num += countInner(&itxn)
Expand All @@ -59,10 +59,10 @@ func (tr TxnRow) Next(ascending bool) (string, error) {
var b [12]byte
binary.LittleEndian.PutUint64(b[:8], tr.Round)

intra := tr.Intra
if tr.Extra.RootIntra != "" {
intra := uint(tr.Intra)
if tr.Extra.RootIntra.Present {
// initialize for descending order, the root intra.
intra, err = strconv.Atoi(tr.Extra.RootIntra)
intra = tr.Extra.RootIntra.Value
if err != nil {
return "", fmt.Errorf("Next() could not parse root intra: %w", err)
}
Expand Down Expand Up @@ -106,13 +106,44 @@ func DecodeTxnRowNext(s string) (round uint64, intra uint32, err error) {
return
}

// OptionalUint wraps bool and uint. It has a custom marshaller below.
type OptionalUint struct {
Present bool
Value uint
}

// MarshalText implements TextMarshaler interface.
func (ou OptionalUint) MarshalText() ([]byte, error) {
if !ou.Present {
return nil, nil
}
return []byte(fmt.Sprintf("%d", ou.Value)), nil
}

// UnmarshalText implements TextUnmarshaler interface.
func (ou *OptionalUint) UnmarshalText(text []byte) error {
if text == nil {
*ou = OptionalUint{}
} else {
value, err := strconv.ParseUint(string(text), 10, 64)
if err != nil {
return err
}
*ou = OptionalUint{
Present: true,
Value: uint(value),
}
}

return nil
}

// TxnExtra is some additional metadata needed for a transaction.
type TxnExtra struct {
AssetCloseAmount uint64 `codec:"aca,omitempty"`
// RootIntra is set on inner transactions. Combined with the confirmation
// RootIntra is set only on inner transactions. Combined with the confirmation
// round it can be used to lookup the root transaction.
// The type is string to allow distinguishing between 0 and empty.
RootIntra string `codec:"root-intra,omitempty"`
RootIntra OptionalUint `codec:"root-intra,omitempty"`
// RootTxid is set on inner transactions. It is a convenience for the
// future. If we decide to return inner transactions we'll want to include
// the root txid.
Expand Down
35 changes: 21 additions & 14 deletions idb/idb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ func TestTxnRowNext(t *testing.T) {
ascending: false,
txnRow: idb.TxnRow{
RootTxnBytes: protocol.Encode(&stxn),
Extra: idb.TxnExtra{RootIntra: "50"},
Intra: 51,
Round: 1_234_567_890,
Extra: idb.TxnExtra{
RootIntra: idb.OptionalUint{Present: true, Value: 50},
},
Intra: 51,
Round: 1_234_567_890,
},
round: 1_234_567_890,
intra: 50,
Expand All @@ -54,9 +56,11 @@ func TestTxnRowNext(t *testing.T) {
ascending: true,
txnRow: idb.TxnRow{
RootTxnBytes: protocol.Encode(&stxn),
Extra: idb.TxnExtra{RootIntra: "50"},
Intra: 51,
Round: 1_234_567_890,
Extra: idb.TxnExtra{
RootIntra: idb.OptionalUint{Present: true, Value: 50},
},
Intra: 51,
Round: 1_234_567_890,
},
round: 1_234_567_890,
intra: 53, // RootIntra + RootTxnBytes.numInnerTxns()
Expand All @@ -66,9 +70,11 @@ func TestTxnRowNext(t *testing.T) {
ascending: true,
txnRow: idb.TxnRow{
RootTxnBytes: []byte{},
Extra: idb.TxnExtra{RootIntra: "50"},
Intra: 51,
Round: 1_234_567_890,
Extra: idb.TxnExtra{
RootIntra: idb.OptionalUint{Present: true, Value: 50},
},
Intra: 51,
Round: 1_234_567_890,
},
errMsg: "could not decode root transaction",
},
Expand All @@ -77,9 +83,11 @@ func TestTxnRowNext(t *testing.T) {
ascending: true,
txnRow: idb.TxnRow{
RootTxnBytes: nil,
Extra: idb.TxnExtra{RootIntra: "50"},
Intra: 51,
Round: 1_234_567_890,
Extra: idb.TxnExtra{
RootIntra: idb.OptionalUint{Present: true, Value: 50},
},
Intra: 51,
Round: 1_234_567_890,
},
errMsg: "was not given transaction bytes",
},
Expand All @@ -88,11 +96,10 @@ func TestTxnRowNext(t *testing.T) {
ascending: true,
txnRow: idb.TxnRow{
RootTxnBytes: []byte{},
Extra: idb.TxnExtra{RootIntra: "not a number"},
Intra: 51,
Round: 1_234_567_890,
},
errMsg: "could not parse root intra",
errMsg: "could not decode root transaction",
},
}

Expand Down
44 changes: 44 additions & 0 deletions idb/postgres/internal/encoding/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"github.com/algorand/go-algorand/protocol"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/algorand/indexer/idb"
)

func TestEncodeSignedTxnWithAD(t *testing.T) {
Expand Down Expand Up @@ -483,3 +485,45 @@ func TestAccountTotalsEncoding(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, totals, totalsNew)
}

func TestTxnExtra(t *testing.T) {
tests := []struct {
name string
extra idb.TxnExtra
expected string
}{
{
name: "basic",
extra: idb.TxnExtra{
AssetCloseAmount: 3,
RootIntra: idb.OptionalUint{Present: true, Value: 4},
RootTxid: "abc",
},
expected: `{"aca":3,"root-intra":"4","root-txid":"abc"}`,
},
{
name: "root_intra_zero",
extra: idb.TxnExtra{
RootIntra: idb.OptionalUint{Present: true, Value: 0},
},
expected: `{"root-intra":"0"}`,
},
{
name: "no_root_intra",
extra: idb.TxnExtra{},
expected: `{}`,
},
}

for _, testcase := range tests {
testcase := testcase
t.Run(testcase.name, func(t *testing.T) {
buf := EncodeTxnExtra(&testcase.extra)
assert.Equal(t, testcase.expected, string(buf))

extraNew, err := DecodeTxnExtra(buf)
require.NoError(t, err)
assert.Equal(t, testcase.extra, extraNew)
})
}
}
12 changes: 6 additions & 6 deletions idb/postgres/internal/writer/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func setSpecialAccounts(addresses transactions.SpecialAddresses, batch *pgx.Batc
// other things too, so it is not clear we should use it. The only
// real benefit is that it would slightly simplify this function by
// allowing us to leave out the intra / block parameters.
func transactionAssetID(txn transactions.SignedTxnWithAD, intra uint64, block *bookkeeping.Block) uint64 {
func transactionAssetID(txn transactions.SignedTxnWithAD, intra uint, block *bookkeeping.Block) uint64 {
assetid := uint64(0)

switch txn.Txn.Type {
Expand All @@ -153,7 +153,7 @@ func transactionAssetID(txn transactions.SignedTxnWithAD, intra uint64, block *b
if assetid == 0 {
// pre v30 transactions do not have ApplyData.ConfigAsset or InnerTxns
// so txn counter + payset pos calculation is OK
assetid = block.TxnCounter - uint64(len(block.Payset)) + intra + 1
assetid = block.TxnCounter - uint64(len(block.Payset)) + uint64(intra) + 1
}
case protocol.AssetConfigTx:
assetid = uint64(txn.ConfigAsset)
Expand All @@ -163,7 +163,7 @@ func transactionAssetID(txn transactions.SignedTxnWithAD, intra uint64, block *b
if assetid == 0 {
// pre v30 transactions do not have ApplyData.ApplicationID or InnerTxns
// so txn counter + payset pos calculation is OK
assetid = block.TxnCounter - uint64(len(block.Payset)) + intra + 1
assetid = block.TxnCounter - uint64(len(block.Payset)) + uint64(intra) + 1
}
case protocol.AssetTransferTx:
assetid = uint64(txn.Txn.XferAsset)
Expand All @@ -177,7 +177,7 @@ func transactionAssetID(txn transactions.SignedTxnWithAD, intra uint64, block *b
// addInnerTransactions traverses the inner transaction tree and adds them to
// the transaction table. It performs a preorder traversal to correctly compute
// the intra round offset, the offset for the next transaction is returned.
func (w *Writer) addInnerTransactions(stxnad *transactions.SignedTxnWithAD, block *bookkeeping.Block, intra, rootIntra uint64, rootTxid string, rows [][]interface{}) (uint64, [][]interface{}, error) {
func (w *Writer) addInnerTransactions(stxnad *transactions.SignedTxnWithAD, block *bookkeeping.Block, intra, rootIntra uint, rootTxid string, rows [][]interface{}) (uint, [][]interface{}, error) {
var err error
for _, itxn := range stxnad.ApplyData.EvalDelta.InnerTxns {
txn := &itxn.Txn
Expand All @@ -188,7 +188,7 @@ func (w *Writer) addInnerTransactions(stxnad *transactions.SignedTxnWithAD, bloc
assetid := transactionAssetID(itxn, 0, nil)
extra := idb.TxnExtra{
AssetCloseAmount: itxn.ApplyData.AssetClosingAmount,
RootIntra: fmt.Sprintf("%d", rootIntra),
RootIntra: idb.OptionalUint{Present: true, Value: rootIntra},
RootTxid: rootTxid,
}

Expand Down Expand Up @@ -219,7 +219,7 @@ func (w *Writer) addInnerTransactions(stxnad *transactions.SignedTxnWithAD, bloc
func (w *Writer) addTransactions(block *bookkeeping.Block, modifiedTxns []transactions.SignedTxnInBlock) error {
var rows [][]interface{}

intra := uint64(0)
intra := uint(0)
for idx, stib := range block.Payset {
var stxnad transactions.SignedTxnWithAD
var err error
Expand Down

0 comments on commit ad96531

Please sign in to comment.