Skip to content

Commit

Permalink
Merge branch 'spendable-change-vtxo' into debug-round-musig-failed
Browse files Browse the repository at this point in the history
  • Loading branch information
altafan committed Sep 19, 2024
2 parents 0d3069e + 5e7c816 commit b92d3b6
Show file tree
Hide file tree
Showing 21 changed files with 358 additions and 344 deletions.
3 changes: 3 additions & 0 deletions api-spec/openapi/swagger/ark/v1/service.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,9 @@
"amount": {
"type": "string",
"format": "uint64"
},
"pendingChange": {
"type": "boolean"
}
}
}
Expand Down
1 change: 1 addition & 0 deletions api-spec/protobuf/ark/v1/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ message Vtxo {
bool pending = 8;
PendingPayment pending_data = 9;
uint64 amount = 10;
bool pending_change = 11;
}

message PendingPayment {
Expand Down
310 changes: 160 additions & 150 deletions api-spec/protobuf/gen/ark/v1/service.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pkg/client-sdk/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ type Vtxo struct {
RedeemTx string
UnconditionalForfeitTxs []string
Pending bool
PendingChange bool
SpentBy string
}

Expand Down
1 change: 1 addition & 0 deletions pkg/client-sdk/client/grpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ func (v vtxo) toVtxo() client.Vtxo {
RoundTxid: v.GetPoolTxid(),
ExpiresAt: expiresAt,
Pending: v.GetPending(),
PendingChange: v.GetPendingChange(),
RedeemTx: redeemTx,
UnconditionalForfeitTxs: uncondForfeitTxs,
SpentBy: v.GetSpentBy(),
Expand Down
1 change: 1 addition & 0 deletions pkg/client-sdk/client/rest/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ func (a *restClient) ListVtxos(
RoundTxid: v.PoolTxid,
ExpiresAt: expiresAt,
Pending: v.Pending,
PendingChange: v.PendingChange,
RedeemTx: redeemTx,
UnconditionalForfeitTxs: uncondForfeitTxs,
SpentBy: v.SpentBy,
Expand Down
3 changes: 3 additions & 0 deletions pkg/client-sdk/client/rest/service/models/v1_vtxo.go

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

36 changes: 12 additions & 24 deletions pkg/client-sdk/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ func TestVtxosToTxs(t *testing.T) {
RoundTxid: "377fa2fbd27c82bdbc095478384c88b6c75432c0ef464189e49c965194446cdf",
Amount: 20000,
Type: TxReceived,
Pending: false,
Claimed: true,
IsPending: false,
CreatedAt: time.Unix(1726054898, 0),
},
},
Expand All @@ -39,16 +38,14 @@ func TestVtxosToTxs(t *testing.T) {
RoundTxid: "377fa2fbd27c82bdbc095478384c88b6c75432c0ef464189e49c965194446cdf",
Amount: 20000,
Type: TxReceived,
Pending: false,
Claimed: true,
IsPending: false,
CreatedAt: time.Unix(1726054898, 0),
},
{
RedeemTxid: "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
Amount: 1000,
Type: TxSent,
Pending: true,
Claimed: false,
IsPending: true,
CreatedAt: time.Unix(1726054898, 0),
},
},
Expand All @@ -61,16 +58,14 @@ func TestVtxosToTxs(t *testing.T) {
RedeemTxid: "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
Amount: 2000,
Type: TxReceived,
Pending: true,
Claimed: false,
IsPending: true,
CreatedAt: time.Unix(1726486359, 0),
},
{
RedeemTxid: "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
Amount: 1000,
Type: TxReceived,
Pending: true,
Claimed: false,
IsPending: true,
CreatedAt: time.Unix(1726054898, 0),
},
},
Expand All @@ -83,16 +78,14 @@ func TestVtxosToTxs(t *testing.T) {
RedeemTxid: "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
Amount: 2000,
Type: TxReceived,
Pending: false,
Claimed: true,
IsPending: false,
CreatedAt: time.Unix(1726486359, 0),
},
{
RedeemTxid: "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
Amount: 1000,
Type: TxReceived,
Pending: false,
Claimed: true,
IsPending: false,
CreatedAt: time.Unix(1726054898, 0),
},
},
Expand All @@ -105,24 +98,21 @@ func TestVtxosToTxs(t *testing.T) {
RedeemTxid: "23c3a885f0ea05f7bdf83f3bf7f8ac9dc3f791ad292f4e63a6f53fa5e4935ab0",
Amount: 2100,
Type: TxSent,
Pending: true,
Claimed: false,
IsPending: true,
CreatedAt: time.Unix(1726503865, 0),
},
{
RedeemTxid: "766fc46ba5c2da41cd4c4bc0566e0f4e0f24c184c41acd3bead5cd7b11120367",
Amount: 2000,
Type: TxReceived,
Pending: false,
Claimed: true,
IsPending: false,
CreatedAt: time.Unix(1726486359, 0),
},
{
RedeemTxid: "94fa598302f17f00c8881e742ec0ce2f8c8d16f3d54fe6ba0fb7d13a493d84ad",
Amount: 1000,
Type: TxReceived,
Pending: false,
Claimed: true,
IsPending: false,
CreatedAt: time.Unix(1726054898, 0),
},
},
Expand All @@ -146,8 +136,7 @@ func TestVtxosToTxs(t *testing.T) {
require.Equal(t, wantTx.RedeemTxid, gotTx.RedeemTxid)
require.Equal(t, int(wantTx.Amount), int(gotTx.Amount))
require.Equal(t, wantTx.Type, gotTx.Type)
require.Equal(t, wantTx.Pending, gotTx.Pending)
require.Equal(t, wantTx.Claimed, gotTx.Claimed)
require.Equal(t, wantTx.IsPending, gotTx.IsPending)
}
})
}
Expand Down Expand Up @@ -276,8 +265,7 @@ func loadFixtures(jsonStr string) (vtxos, []Transaction, error) {
RoundTxid: tx.RoundTxid,
Amount: tx.Amount,
Type: TxReceived,
Pending: tx.Pending,
Claimed: tx.Claimed,
IsPending: tx.Pending,
CreatedAt: createdAt,
}
}
Expand Down
15 changes: 0 additions & 15 deletions pkg/client-sdk/covenant_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1677,16 +1677,10 @@ func (a *covenantArkClient) getBoardingTxs(ctx context.Context) (transactions []
}

for _, u := range allUtxos {
pending := false
if isPending[u.Txid] {
pending = true
}
transactions = append(transactions, Transaction{
BoardingTxid: u.Txid,
Amount: u.Amount,
Type: TxReceived,
Pending: pending,
Claimed: !pending,
CreatedAt: u.CreatedAt,
})
}
Expand Down Expand Up @@ -1726,13 +1720,6 @@ func vtxosToTxsCovenant(
if amount < 0 {
txType = TxSent
}
// check if is a pending tx
pending := false
claimed := true
if len(v.RoundTxid) == 0 && len(v.SpentBy) == 0 {
pending = true
claimed = false
}
// get redeem txid
redeemTxid := ""
if len(v.RedeemTx) > 0 {
Expand All @@ -1748,8 +1735,6 @@ func vtxosToTxsCovenant(
RedeemTxid: redeemTxid,
Amount: uint64(math.Abs(float64(amount))),
Type: txType,
Pending: pending,
Claimed: claimed,
CreatedAt: getCreatedAtFromExpiry(roundLifetime, *v.ExpiresAt),
})
}
Expand Down
102 changes: 61 additions & 41 deletions pkg/client-sdk/covenantless_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,20 @@ func (a *covenantlessArkClient) ListVtxos(
return
}

_, pubkey, _, err := common.DecodeAddress(offchainAddrs[0])
if err != nil {
return
}

myPubkey := schnorr.SerializePubKey(pubkey)

// The ASP returns the vtxos sent to others via async payments as spendable
// because they are actually revertable. Since we do not provide any revert
// feature, we want to ignore them.
// To understand if the output of a redeem tx is sent or received we look at
// the inputs and check if they are owned by us.
// The auxiliary variables below are used to make these checks in an
// efficient way.
indexedSpentVtxos := make(map[string]client.Vtxo)
pendingVtxos := make([]client.Vtxo, 0)
keyTempl := "%s:%d"
for _, addr := range offchainAddrs {
spendable, spent, err := a.client.ListVtxos(ctx, addr)
if err != nil {
Expand All @@ -167,23 +171,35 @@ func (a *covenantlessArkClient) ListVtxos(
spendableVtxos = append(spendableVtxos, v)
continue
}
pendingVtxos = append(pendingVtxos, v)
script, err := bitcointree.ParseVtxoScript(v.Descriptor)
if err != nil {
return nil, nil, err
}

reversibleVtxo, ok := script.(*bitcointree.ReversibleVtxoScript)
if !ok {
spendableVtxos = append(spendableVtxos, v)
continue
}

if !bytes.Equal(schnorr.SerializePubKey(reversibleVtxo.Sender), myPubkey) {
spendableVtxos = append(spendableVtxos, v)
}
}
for _, v := range spent {
indexedSpentVtxos[fmt.Sprintf(keyTempl, v.Txid, v.VOut)] = v
spentVtxos = append(spentVtxos, v)
}
}
script, err := bitcointree.ParseVtxoScript(v.Descriptor)
if err != nil {
return nil, nil, err
}

for _, vtxo := range pendingVtxos {
ptx, err := psbt.NewFromRawBytes(strings.NewReader(vtxo.RedeemTx), true)
if err != nil {
return nil, nil, err
}
input := ptx.UnsignedTx.TxIn[0].PreviousOutPoint
key := fmt.Sprintf(keyTempl, input.Hash.String(), input.Index)
if _, ok := indexedSpentVtxos[key]; !ok {
spendableVtxos = append(spendableVtxos, vtxo)
reversibleVtxo, ok := script.(*bitcointree.ReversibleVtxoScript)
if !ok {
spentVtxos = append(spentVtxos, v)
continue
}
if !bytes.Equal(schnorr.SerializePubKey(reversibleVtxo.Sender), myPubkey) {
spentVtxos = append(spentVtxos, v)
}
}
}

Expand Down Expand Up @@ -334,6 +350,21 @@ func (a *covenantlessArkClient) Balance(
},
}

history, _ := a.GetTransactionHistory(ctx)
log.Info("history ", len(history))
for _, v := range history {
log.Info("---------")
log.Infof("RoundTxid %v", v.RoundTxid)
log.Infof("RedeemTxid %v", v.RedeemTxid)
log.Infof("BoardingTxid %v", v.BoardingTxid)
log.Infof("CreatedAt %s", v.CreatedAt)
log.Infof("Type %v", v.Type)
log.Infof("Amount %d", v.Amount)
log.Infof("Pending %v", v.IsPending)
log.Infof("PendingChange %v", v.IsPendingChange)
log.Info("---------")
}

return response, nil
}

Expand Down Expand Up @@ -1746,12 +1777,11 @@ func (a *covenantlessArkClient) getOffchainBalance(
) (uint64, map[int64]uint64, error) {
amountByExpiration := make(map[int64]uint64, 0)

spendableVtxos, pendingVtxos, err := a.getVtxos(ctx, addr, computeVtxoExpiration)
vtxos, _, err := a.getVtxos(ctx, addr, computeVtxoExpiration)
if err != nil {
return 0, nil, err
}
var balance uint64
vtxos := append(spendableVtxos, pendingVtxos...)
for _, vtxo := range vtxos {
balance += vtxo.Amount

Expand Down Expand Up @@ -1856,19 +1886,16 @@ func (a *covenantlessArkClient) getClaimableBoardingUtxos(ctx context.Context) (
func (a *covenantlessArkClient) getVtxos(
ctx context.Context, _ string, computeVtxoExpiration bool,
) ([]client.Vtxo, []client.Vtxo, error) {
vtxos, _, err := a.ListVtxos(ctx)
spendableVtxos, _, err := a.ListVtxos(ctx)
if err != nil {
return nil, nil, err
}

pendingVtxos := make([]client.Vtxo, 0)
spendableVtxos := make([]client.Vtxo, 0)
for _, vtxo := range vtxos {
for _, vtxo := range spendableVtxos {
if vtxo.Pending {
pendingVtxos = append(pendingVtxos, vtxo)
continue
}
spendableVtxos = append(spendableVtxos, vtxo)
}

if !computeVtxoExpiration {
Expand All @@ -1888,7 +1915,7 @@ func (a *covenantlessArkClient) getVtxos(

for i, vtxo := range spendableVtxos {
if vtxo.Txid == vtxoTxid {
vtxos[i].ExpiresAt = expiration
spendableVtxos[i].ExpiresAt = expiration
break
}
}
Expand Down Expand Up @@ -2016,8 +2043,7 @@ func (a *covenantlessArkClient) getBoardingTxs(ctx context.Context) (transaction
BoardingTxid: u.Txid,
Amount: u.Amount,
Type: TxReceived,
Pending: pending,
Claimed: !pending,
IsPending: pending,
CreatedAt: u.CreatedAt,
})
}
Expand Down Expand Up @@ -2067,13 +2093,7 @@ func vtxosToTxsCovenantless(
if amount < 0 {
txType = TxSent
}
// check if is a pending tx
pending := false
claimed := true
if len(v.RoundTxid) == 0 && len(v.SpentBy) == 0 {
pending = true
claimed = false
}

// get redeem txid
redeemTxid := ""
if len(v.RedeemTx) > 0 {
Expand All @@ -2085,13 +2105,13 @@ func vtxosToTxsCovenantless(
}
// add transaction
transactions = append(transactions, Transaction{
RoundTxid: v.RoundTxid,
RedeemTxid: redeemTxid,
Amount: uint64(math.Abs(float64(amount))),
Type: txType,
Pending: pending,
Claimed: claimed,
CreatedAt: getCreatedAtFromExpiry(roundLifetime, *v.ExpiresAt),
RoundTxid: v.RoundTxid,
RedeemTxid: redeemTxid,
Amount: uint64(math.Abs(float64(amount))),
Type: txType,
IsPending: v.Pending,
IsPendingChange: v.PendingChange,
CreatedAt: getCreatedAtFromExpiry(roundLifetime, *v.ExpiresAt),
})
}

Expand Down
Loading

0 comments on commit b92d3b6

Please sign in to comment.