Skip to content

Commit 2159558

Browse files
committed
Merge branch 'multi-address-output-support' into 'main'
Multi address output support See merge request flarenetwork/network/flare-p-chain-indexer!4
2 parents e2d0849 + 7a97762 commit 2159558

File tree

4 files changed

+108
-13
lines changed

4 files changed

+108
-13
lines changed

indexer/shared/base_tx.go

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,22 @@ import (
1111
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
1212
)
1313

14-
// Create database outputs from TransferableOutputs, provided their type is *secp256k1fx.TransferOutput and the
15-
// number of addresses for each output is 1. Error is returned if these two conditions
16-
// are not met.
17-
func OutputsFromTxOuts(txID string, outs []*avax.TransferableOutput, startIndex int, creator OutputCreator) ([]Output, error) {
18-
txOuts := make([]Output, len(outs))
14+
// Create database outputs from TransferableOutputs, provided their type is *secp256k1fx.TransferOutput
15+
func OutputsFromTxOuts(
16+
txID string,
17+
outs []*avax.TransferableOutput,
18+
startIndex int,
19+
creator OutputCreator,
20+
) ([]Output, error) {
21+
txOuts := make([]Output, 0, len(outs))
1922
for outi, cout := range outs {
20-
dbOut := &database.TxOutput{
21-
TxID: txID,
22-
Idx: uint32(outi + startIndex),
23-
}
24-
err := UpdateTransferableOutput(dbOut, cout.Out)
23+
dbOuts, err := CreateTransferableOutputs(txID, uint32(outi+startIndex), cout.Out)
2524
if err != nil {
2625
return nil, err
2726
}
28-
txOuts[outi] = creator.CreateOutput(dbOut)
27+
for _, dbOut := range dbOuts {
28+
txOuts = append(txOuts, creator.CreateOutput(dbOut))
29+
}
2930
}
3031
return txOuts, nil
3132
}
@@ -69,6 +70,34 @@ func UpdateTransferableOutput(dbOut *database.TxOutput, out verify.State) error
6970
return nil
7071
}
7172

73+
// Create database outputs from out provided its type is *secp256k1fx.TransferOutput.
74+
// Note that multiple database outputs are created if there are multiple addresses in out.
75+
func CreateTransferableOutputs(
76+
txID string,
77+
idx uint32,
78+
out verify.State,
79+
) ([]*database.TxOutput, error) {
80+
to, ok := out.(*secp256k1fx.TransferOutput)
81+
if !ok {
82+
return nil, fmt.Errorf("TransferableOutput has unsupported type")
83+
}
84+
dbOuts := make([]*database.TxOutput, len(to.Addrs))
85+
for i, addr := range to.Addrs {
86+
formattedAddr, err := chain.FormatAddressBytes(addr.Bytes())
87+
if err != nil {
88+
return nil, err
89+
}
90+
dbOut := &database.TxOutput{
91+
TxID: txID,
92+
Idx: idx,
93+
Amount: to.Amount(),
94+
Address: formattedAddr,
95+
}
96+
dbOuts[i] = dbOut
97+
}
98+
return dbOuts, nil
99+
}
100+
72101
// Return address from Owner interface provided its type is *secp256k1fx.OutputOwners and the
73102
// number of addresses is 1. Error is returned if these two conditions are not met.
74103
func RewardsOwnerAddress(owner fx.Owner) (string, error) {

indexer/shared/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
)
66

77
const (
8-
ApplicationVersion = "2.2.2"
8+
ApplicationVersion = "2.2.3-rc1"
99
)
1010

1111
var (

utils/staking/utils.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,15 @@ func DedupeTxs(txs []database.PChainTxData) []database.PChainTxData {
200200
continue
201201
}
202202

203-
txSet[*tx.TxID] = tx
203+
if setTx, exists := txSet[*tx.TxID]; exists {
204+
// If there is already a tx with this txID and index 0, keep the one with the
205+
// lexically smallest input address
206+
if tx.InputAddress < setTx.InputAddress {
207+
txSet[*tx.TxID] = tx
208+
}
209+
} else {
210+
txSet[*tx.TxID] = tx
211+
}
204212
}
205213

206214
dedupedTxs := make([]database.PChainTxData, 0, len(txSet))

utils/staking/utils_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package staking
2+
3+
import (
4+
"flare-indexer/database"
5+
"testing"
6+
)
7+
8+
func testPChainTxData(id uint64, txID string, inputAddress string, inputIndex int) database.PChainTxData {
9+
tx := database.PChainTxData{
10+
PChainTx: database.PChainTx{
11+
BaseEntity: database.BaseEntity{ID: id},
12+
TxID: &txID,
13+
},
14+
InputAddress: inputAddress,
15+
InputIndex: uint32(inputIndex),
16+
}
17+
return tx
18+
}
19+
20+
func TestDedupeTxs(t *testing.T) {
21+
testPChainTxData := []database.PChainTxData{
22+
testPChainTxData(1, "tx1", "addr2", 0),
23+
testPChainTxData(2, "tx1", "addr1", 0),
24+
testPChainTxData(3, "tx1", "addr3", 1),
25+
testPChainTxData(4, "tx2", "addr4", 0),
26+
testPChainTxData(6, "tx3", "addr1", 0),
27+
testPChainTxData(5, "tx3", "addr2", 0),
28+
testPChainTxData(7, "tx3", "addr6", 1),
29+
testPChainTxData(8, "tx3", "addr7", 1),
30+
testPChainTxData(9, "tx4", "addr1", 0),
31+
testPChainTxData(10, "tx4", "addr2", 0),
32+
}
33+
34+
dedupedTxs := DedupeTxs(testPChainTxData)
35+
36+
expectedSequence := [][]string{
37+
{"tx1", "addr1"},
38+
{"tx2", "addr4"},
39+
{"tx3", "addr1"},
40+
{"tx4", "addr1"},
41+
}
42+
43+
if len(dedupedTxs) != len(expectedSequence) {
44+
t.Fatalf("Expected %d deduped txs, got %d", len(expectedSequence), len(dedupedTxs))
45+
}
46+
47+
for i, tx := range dedupedTxs {
48+
expectedTxID := expectedSequence[i][0]
49+
expectedAddress := expectedSequence[i][1]
50+
if *tx.TxID != expectedTxID {
51+
t.Errorf("At index %d, expected TxID %s, got %s", i, expectedTxID, *tx.TxID)
52+
}
53+
if tx.InputAddress != expectedAddress {
54+
t.Errorf("At index %d, expected InputAddress %s, got %s", i, expectedAddress, tx.InputAddress)
55+
}
56+
}
57+
58+
}

0 commit comments

Comments
 (0)