mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-18 12:44:19 +01:00
New address encoding (#356)
* [common] rework address encoding * new address encoding * replace offchain address by vtxo output key in DB * merge migrations files into init one * fix txbuilder fixtures * fix transaction events
This commit is contained in:
@@ -156,6 +156,7 @@ func (s *covenantService) GetBoardingAddress(ctx context.Context, userPubkey *se
|
||||
func (s *covenantService) SpendVtxos(ctx context.Context, inputs []ports.Input) (string, error) {
|
||||
vtxosInputs := make([]domain.Vtxo, 0)
|
||||
boardingInputs := make([]ports.BoardingInput, 0)
|
||||
descriptors := make(map[domain.VtxoKey]string)
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
@@ -218,13 +219,14 @@ func (s *covenantService) SpendVtxos(ctx context.Context, inputs []ports.Input)
|
||||
}
|
||||
|
||||
vtxosInputs = append(vtxosInputs, vtxo)
|
||||
descriptors[vtxo.VtxoKey] = input.Descriptor
|
||||
}
|
||||
|
||||
payment, err := domain.NewPayment(vtxosInputs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := s.paymentRequests.push(*payment, boardingInputs); err != nil {
|
||||
if err := s.paymentRequests.push(*payment, boardingInputs, descriptors); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return payment.Id, nil
|
||||
@@ -324,7 +326,7 @@ func (s *covenantService) CompleteAsyncPayment(ctx context.Context, redeemTx str
|
||||
return fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
func (s *covenantService) CreateAsyncPayment(ctx context.Context, inputs []ports.Input, receivers []domain.Receiver) (string, error) {
|
||||
func (s *covenantService) CreateAsyncPayment(_ context.Context, _ []AsyncPaymentInput, _ []domain.Receiver) (string, error) {
|
||||
return "", fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
@@ -345,9 +347,14 @@ func (s *covenantService) SignRoundTx(ctx context.Context, signedRoundTx string)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *covenantService) ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, []domain.Vtxo, error) {
|
||||
pk := hex.EncodeToString(pubkey.SerializeCompressed())
|
||||
return s.repoManager.Vtxos().GetAllVtxos(ctx, pk)
|
||||
func (s *covenantService) ListVtxos(ctx context.Context, address string) ([]domain.Vtxo, []domain.Vtxo, error) {
|
||||
decodedAddress, err := common.DecodeAddress(address)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to decode address: %s", err)
|
||||
}
|
||||
pubkey := hex.EncodeToString(schnorr.SerializePubKey(decodedAddress.VtxoTapKey))
|
||||
|
||||
return s.repoManager.Vtxos().GetAllVtxos(ctx, pubkey)
|
||||
}
|
||||
|
||||
func (s *covenantService) GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent {
|
||||
@@ -482,7 +489,7 @@ func (s *covenantService) startFinalization() {
|
||||
if num > paymentsThreshold {
|
||||
num = paymentsThreshold
|
||||
}
|
||||
payments, boardingInputs, _ := s.paymentRequests.pop(num)
|
||||
payments, boardingInputs, descriptors, _ := s.paymentRequests.pop(num)
|
||||
if _, err := round.RegisterPayments(payments); err != nil {
|
||||
round.Fail(fmt.Errorf("failed to register payments: %s", err))
|
||||
log.WithError(err).Warn("failed to register payments")
|
||||
@@ -517,7 +524,7 @@ func (s *covenantService) startFinalization() {
|
||||
minRelayFeeRate := s.wallet.MinRelayFeeRate(ctx)
|
||||
|
||||
if needForfeits {
|
||||
connectors, forfeitTxs, err = s.builder.BuildForfeitTxs(unsignedPoolTx, payments, minRelayFeeRate)
|
||||
connectors, forfeitTxs, err = s.builder.BuildForfeitTxs(unsignedPoolTx, payments, descriptors, minRelayFeeRate)
|
||||
if err != nil {
|
||||
round.Fail(fmt.Errorf("failed to create connectors and forfeit txs: %s", err))
|
||||
log.WithError(err).Warn("failed to create connectors and forfeit txs")
|
||||
@@ -933,53 +940,20 @@ func (s *covenantService) getNewVtxos(round *domain.Round) []domain.Vtxo {
|
||||
continue // skip fee outputs
|
||||
}
|
||||
|
||||
desc := ""
|
||||
found := false
|
||||
|
||||
for _, p := range round.Payments {
|
||||
if found {
|
||||
break
|
||||
}
|
||||
|
||||
for _, r := range p.Receivers {
|
||||
if r.IsOnchain() {
|
||||
continue
|
||||
}
|
||||
|
||||
vtxoScript, err := tree.ParseVtxoScript(r.Descriptor)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("failed to parse vtxo descriptor")
|
||||
continue
|
||||
}
|
||||
|
||||
tapKey, _, err := vtxoScript.TapTree()
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("failed to compute vtxo tap key")
|
||||
continue
|
||||
}
|
||||
|
||||
script, err := common.P2TRScript(tapKey)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("failed to create vtxo scriptpubkey")
|
||||
continue
|
||||
}
|
||||
|
||||
if bytes.Equal(script, out.Script) {
|
||||
found = true
|
||||
desc = r.Descriptor
|
||||
break
|
||||
}
|
||||
}
|
||||
vtxoTapKey, err := schnorr.ParsePubKey(out.Script[2:])
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("failed to parse vtxo tap key")
|
||||
continue
|
||||
}
|
||||
|
||||
if found {
|
||||
vtxos = append(vtxos, domain.Vtxo{
|
||||
VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)},
|
||||
Receiver: domain.Receiver{Descriptor: desc, Amount: uint64(out.Value)},
|
||||
RoundTxid: round.Txid,
|
||||
})
|
||||
break
|
||||
}
|
||||
vtxoPubkey := hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey))
|
||||
|
||||
vtxos = append(vtxos, domain.Vtxo{
|
||||
VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)},
|
||||
Pubkey: vtxoPubkey,
|
||||
Amount: uint64(out.Value),
|
||||
RoundTxid: round.Txid,
|
||||
})
|
||||
}
|
||||
}
|
||||
return vtxos
|
||||
@@ -1050,17 +1024,17 @@ func (s *covenantService) restoreWatchingVtxos() error {
|
||||
func (s *covenantService) extractVtxosScripts(vtxos []domain.Vtxo) ([]string, error) {
|
||||
indexedScripts := make(map[string]struct{})
|
||||
for _, vtxo := range vtxos {
|
||||
vtxoScript, err := tree.ParseVtxoScript(vtxo.Receiver.Descriptor)
|
||||
vtxoTapKeyBytes, err := hex.DecodeString(vtxo.Pubkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tapKey, _, err := vtxoScript.TapTree()
|
||||
vtxoTapKey, err := schnorr.ParsePubKey(vtxoTapKeyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
script, err := common.P2TRScript(tapKey)
|
||||
script, err := common.P2TRScript(vtxoTapKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/btcutil/psbt"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
@@ -177,37 +178,28 @@ func (s *covenantlessService) CompleteAsyncPayment(
|
||||
|
||||
// verify that the vtxo is spendable
|
||||
|
||||
vtxo, err := vtxoRepo.GetVtxos(ctx, []domain.VtxoKey{{Txid: vtxoOutpoint.Hash.String(), VOut: vtxoOutpoint.Index}})
|
||||
vtxos, err := vtxoRepo.GetVtxos(ctx, []domain.VtxoKey{{Txid: vtxoOutpoint.Hash.String(), VOut: vtxoOutpoint.Index}})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get vtxo: %s", err)
|
||||
}
|
||||
|
||||
if len(vtxo) == 0 {
|
||||
if len(vtxos) == 0 {
|
||||
return fmt.Errorf("vtxo not found")
|
||||
}
|
||||
|
||||
if vtxo[0].Spent {
|
||||
vtxo := vtxos[0]
|
||||
if vtxo.Spent {
|
||||
return fmt.Errorf("vtxo already spent")
|
||||
}
|
||||
|
||||
if vtxo[0].Redeemed {
|
||||
if vtxo.Redeemed {
|
||||
return fmt.Errorf("vtxo already redeemed")
|
||||
}
|
||||
|
||||
if vtxo[0].Swept {
|
||||
if vtxo.Swept {
|
||||
return fmt.Errorf("vtxo already swept")
|
||||
}
|
||||
|
||||
vtxoScript, err := bitcointree.ParseVtxoScript(vtxo[0].Descriptor)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse vtxo script: %s", err)
|
||||
}
|
||||
|
||||
vtxoTapKey, _, err := vtxoScript.TapTree()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get taproot key: %s", err)
|
||||
}
|
||||
|
||||
// verify that the user signs a forfeit closure
|
||||
var userPubKey *secp256k1.PublicKey
|
||||
|
||||
@@ -228,6 +220,16 @@ func (s *covenantlessService) CompleteAsyncPayment(
|
||||
return fmt.Errorf("redeem transaction is not signed")
|
||||
}
|
||||
|
||||
vtxoPublicKeyBytes, err := hex.DecodeString(vtxo.Pubkey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode vtxo pubkey: %s", err)
|
||||
}
|
||||
|
||||
vtxoTapKey, err := schnorr.ParsePubKey(vtxoPublicKeyBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse vtxo pubkey: %s", err)
|
||||
}
|
||||
|
||||
// verify witness utxo
|
||||
pkscript, err := common.P2TRScript(vtxoTapKey)
|
||||
if err != nil {
|
||||
@@ -238,7 +240,7 @@ func (s *covenantlessService) CompleteAsyncPayment(
|
||||
return fmt.Errorf("witness utxo script mismatch")
|
||||
}
|
||||
|
||||
if input.WitnessUtxo.Value != int64(vtxo[0].Amount) {
|
||||
if input.WitnessUtxo.Value != int64(vtxo.Amount) {
|
||||
return fmt.Errorf("witness utxo value mismatch")
|
||||
}
|
||||
}
|
||||
@@ -260,19 +262,23 @@ func (s *covenantlessService) CompleteAsyncPayment(
|
||||
vtxos := make([]domain.Vtxo, 0, len(asyncPayData.receivers))
|
||||
|
||||
for outIndex, out := range redeemPtx.UnsignedTx.TxOut {
|
||||
desc := asyncPayData.receivers[outIndex].Descriptor
|
||||
_, _, _, _, err := descriptor.ParseReversibleVtxoDescriptor(desc)
|
||||
isPending := err == nil
|
||||
vtxoTapKey, err := schnorr.ParsePubKey(out.PkScript[2:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse vtxo taproot key: %s", err)
|
||||
}
|
||||
|
||||
vtxoPubkey := hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey))
|
||||
|
||||
// all pending except the last one
|
||||
isPending := outIndex < len(asyncPayData.receivers)-1
|
||||
|
||||
vtxos = append(vtxos, domain.Vtxo{
|
||||
VtxoKey: domain.VtxoKey{
|
||||
Txid: redeemTxid,
|
||||
VOut: uint32(outIndex),
|
||||
},
|
||||
Receiver: domain.Receiver{
|
||||
Descriptor: desc,
|
||||
Amount: uint64(out.Value),
|
||||
},
|
||||
Pubkey: vtxoPubkey,
|
||||
Amount: uint64(out.Value),
|
||||
ExpireAt: asyncPayData.expireAt,
|
||||
RedeemTx: redeemTx,
|
||||
Pending: isPending,
|
||||
@@ -309,11 +315,16 @@ func (s *covenantlessService) CompleteAsyncPayment(
|
||||
}
|
||||
|
||||
func (s *covenantlessService) CreateAsyncPayment(
|
||||
ctx context.Context, inputs []ports.Input, receivers []domain.Receiver,
|
||||
ctx context.Context, inputs []AsyncPaymentInput, receivers []domain.Receiver,
|
||||
) (string, error) {
|
||||
vtxosKeys := make([]domain.VtxoKey, 0, len(inputs))
|
||||
descriptors := make(map[domain.VtxoKey]string)
|
||||
forfeitLeaves := make(map[domain.VtxoKey]chainhash.Hash)
|
||||
|
||||
for _, in := range inputs {
|
||||
vtxosKeys = append(vtxosKeys, in.VtxoKey)
|
||||
descriptors[in.VtxoKey] = in.Descriptor
|
||||
forfeitLeaves[in.VtxoKey] = in.ForfeitLeafHash
|
||||
}
|
||||
|
||||
vtxos, err := s.repoManager.Vtxos().GetVtxos(ctx, vtxosKeys)
|
||||
@@ -351,7 +362,7 @@ func (s *covenantlessService) CreateAsyncPayment(
|
||||
}
|
||||
|
||||
redeemTx, err := s.builder.BuildAsyncPaymentTransactions(
|
||||
vtxosInputs, s.pubkey, receivers,
|
||||
vtxosInputs, descriptors, forfeitLeaves, receivers,
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to build async payment txs: %s", err)
|
||||
@@ -404,7 +415,7 @@ func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []ports.Inp
|
||||
now := time.Now().Unix()
|
||||
|
||||
boardingTxs := make(map[string]wire.MsgTx, 0) // txid -> txhex
|
||||
|
||||
descriptors := make(map[domain.VtxoKey]string)
|
||||
for _, input := range inputs {
|
||||
vtxosResult, err := s.repoManager.Vtxos().GetVtxos(ctx, []domain.VtxoKey{input.VtxoKey})
|
||||
if err != nil || len(vtxosResult) == 0 {
|
||||
@@ -461,6 +472,8 @@ func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []ports.Inp
|
||||
return "", fmt.Errorf("input %s:%d already swept", vtxo.Txid, vtxo.VOut)
|
||||
}
|
||||
|
||||
descriptors[vtxo.VtxoKey] = input.Descriptor
|
||||
|
||||
vtxosInputs = append(vtxosInputs, vtxo)
|
||||
}
|
||||
|
||||
@@ -468,7 +481,7 @@ func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []ports.Inp
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := s.paymentRequests.push(*payment, boardingInputs); err != nil {
|
||||
if err := s.paymentRequests.push(*payment, boardingInputs, descriptors); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return payment.Id, nil
|
||||
@@ -572,9 +585,14 @@ func (s *covenantlessService) SignRoundTx(ctx context.Context, signedRoundTx str
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *covenantlessService) ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, []domain.Vtxo, error) {
|
||||
pk := hex.EncodeToString(pubkey.SerializeCompressed())
|
||||
return s.repoManager.Vtxos().GetAllVtxos(ctx, pk)
|
||||
func (s *covenantlessService) ListVtxos(ctx context.Context, address string) ([]domain.Vtxo, []domain.Vtxo, error) {
|
||||
decodedAddress, err := common.DecodeAddress(address)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to decode address: %s", err)
|
||||
}
|
||||
pubkey := hex.EncodeToString(schnorr.SerializePubKey(decodedAddress.VtxoTapKey))
|
||||
|
||||
return s.repoManager.Vtxos().GetAllVtxos(ctx, pubkey)
|
||||
}
|
||||
|
||||
func (s *covenantlessService) GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent {
|
||||
@@ -771,7 +789,7 @@ func (s *covenantlessService) startFinalization() {
|
||||
if num > paymentsThreshold {
|
||||
num = paymentsThreshold
|
||||
}
|
||||
payments, boardingInputs, cosigners := s.paymentRequests.pop(num)
|
||||
payments, boardingInputs, descriptors, cosigners := s.paymentRequests.pop(num)
|
||||
if len(payments) > len(cosigners) {
|
||||
err := fmt.Errorf("missing ephemeral key for payments")
|
||||
round.Fail(fmt.Errorf("round aborted: %s", err))
|
||||
@@ -973,7 +991,7 @@ func (s *covenantlessService) startFinalization() {
|
||||
minRelayFeeRate := s.wallet.MinRelayFeeRate(ctx)
|
||||
|
||||
if needForfeits {
|
||||
connectors, forfeitTxs, err = s.builder.BuildForfeitTxs(unsignedRoundTx, payments, minRelayFeeRate)
|
||||
connectors, forfeitTxs, err = s.builder.BuildForfeitTxs(unsignedRoundTx, payments, descriptors, minRelayFeeRate)
|
||||
if err != nil {
|
||||
round.Fail(fmt.Errorf("failed to create connectors and forfeit txs: %s", err))
|
||||
log.WithError(err).Warn("failed to create connectors and forfeit txs")
|
||||
@@ -1332,53 +1350,18 @@ func (s *covenantlessService) getNewVtxos(round *domain.Round) []domain.Vtxo {
|
||||
continue
|
||||
}
|
||||
for i, out := range tx.UnsignedTx.TxOut {
|
||||
desc := ""
|
||||
found := false
|
||||
|
||||
for _, p := range round.Payments {
|
||||
if found {
|
||||
break
|
||||
}
|
||||
|
||||
for _, r := range p.Receivers {
|
||||
if r.IsOnchain() {
|
||||
continue
|
||||
}
|
||||
|
||||
vtxoScript, err := bitcointree.ParseVtxoScript(r.Descriptor)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("failed to parse vtxo descriptor")
|
||||
continue
|
||||
}
|
||||
|
||||
tapKey, _, err := vtxoScript.TapTree()
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("failed to compute vtxo tap key")
|
||||
continue
|
||||
}
|
||||
|
||||
script, err := common.P2TRScript(tapKey)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("failed to create vtxo scriptpubkey")
|
||||
continue
|
||||
}
|
||||
|
||||
if bytes.Equal(script, out.PkScript) {
|
||||
found = true
|
||||
desc = r.Descriptor
|
||||
break
|
||||
}
|
||||
}
|
||||
vtxoTapKey, err := schnorr.ParsePubKey(out.PkScript[2:])
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("failed to parse vtxo tap key")
|
||||
continue
|
||||
}
|
||||
|
||||
if found {
|
||||
vtxos = append(vtxos, domain.Vtxo{
|
||||
VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)},
|
||||
Receiver: domain.Receiver{Descriptor: desc, Amount: uint64(out.Value)},
|
||||
RoundTxid: round.Txid,
|
||||
})
|
||||
break
|
||||
}
|
||||
vtxos = append(vtxos, domain.Vtxo{
|
||||
VtxoKey: domain.VtxoKey{Txid: node.Txid, VOut: uint32(i)},
|
||||
Pubkey: hex.EncodeToString(schnorr.SerializePubKey(vtxoTapKey)),
|
||||
Amount: uint64(out.Value),
|
||||
RoundTxid: round.Txid,
|
||||
})
|
||||
}
|
||||
}
|
||||
return vtxos
|
||||
@@ -1450,17 +1433,17 @@ func (s *covenantlessService) extractVtxosScripts(vtxos []domain.Vtxo) ([]string
|
||||
indexedScripts := make(map[string]struct{})
|
||||
|
||||
for _, vtxo := range vtxos {
|
||||
vtxoScript, err := bitcointree.ParseVtxoScript(vtxo.Receiver.Descriptor)
|
||||
vtxoTapKeyBytes, err := hex.DecodeString(vtxo.Pubkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tapKey, _, err := vtxoScript.TapTree()
|
||||
vtxoTapKey, err := schnorr.ParsePubKey(vtxoTapKeyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
script, err := common.P2TRScript(tapKey)
|
||||
script, err := common.P2TRScript(vtxoTapKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/ark-network/ark/server/internal/core/domain"
|
||||
"github.com/ark-network/ark/server/internal/core/ports"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
)
|
||||
|
||||
@@ -12,6 +13,11 @@ var (
|
||||
paymentsThreshold = int64(128)
|
||||
)
|
||||
|
||||
type AsyncPaymentInput struct {
|
||||
ports.Input
|
||||
ForfeitLeafHash chainhash.Hash
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
Start() error
|
||||
Stop()
|
||||
@@ -27,12 +33,12 @@ type Service interface {
|
||||
ctx context.Context, paymentId string,
|
||||
) (lastEvent domain.RoundEvent, err error)
|
||||
ListVtxos(
|
||||
ctx context.Context, pubkey *secp256k1.PublicKey,
|
||||
ctx context.Context, address string,
|
||||
) (spendableVtxos, spentVtxos []domain.Vtxo, err error)
|
||||
GetInfo(ctx context.Context) (*ServiceInfo, error)
|
||||
// Async payments
|
||||
CreateAsyncPayment(
|
||||
ctx context.Context, inputs []ports.Input, receivers []domain.Receiver,
|
||||
ctx context.Context, inputs []AsyncPaymentInput, receivers []domain.Receiver,
|
||||
) (string, error)
|
||||
CompleteAsyncPayment(
|
||||
ctx context.Context, redeemTx string,
|
||||
|
||||
@@ -24,13 +24,14 @@ type timedPayment struct {
|
||||
type paymentsMap struct {
|
||||
lock *sync.RWMutex
|
||||
payments map[string]*timedPayment
|
||||
descriptors map[domain.VtxoKey]string
|
||||
ephemeralKeys map[string]*secp256k1.PublicKey
|
||||
}
|
||||
|
||||
func newPaymentsMap() *paymentsMap {
|
||||
paymentsById := make(map[string]*timedPayment)
|
||||
lock := &sync.RWMutex{}
|
||||
return &paymentsMap{lock, paymentsById, make(map[string]*secp256k1.PublicKey)}
|
||||
return &paymentsMap{lock, paymentsById, make(map[domain.VtxoKey]string), make(map[string]*secp256k1.PublicKey)}
|
||||
}
|
||||
|
||||
func (m *paymentsMap) len() int64 {
|
||||
@@ -58,7 +59,11 @@ func (m *paymentsMap) delete(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *paymentsMap) push(payment domain.Payment, boardingInputs []ports.BoardingInput) error {
|
||||
func (m *paymentsMap) push(
|
||||
payment domain.Payment,
|
||||
boardingInputs []ports.BoardingInput,
|
||||
descriptors map[domain.VtxoKey]string,
|
||||
) error {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
@@ -86,6 +91,10 @@ func (m *paymentsMap) push(payment domain.Payment, boardingInputs []ports.Boardi
|
||||
}
|
||||
}
|
||||
|
||||
for key, desc := range descriptors {
|
||||
m.descriptors[key] = desc
|
||||
}
|
||||
|
||||
m.payments[payment.Id] = &timedPayment{payment, boardingInputs, time.Now(), time.Time{}}
|
||||
return nil
|
||||
}
|
||||
@@ -102,7 +111,7 @@ func (m *paymentsMap) pushEphemeralKey(paymentId string, pubkey *secp256k1.Publi
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, []*secp256k1.PublicKey) {
|
||||
func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, map[domain.VtxoKey]string, []*secp256k1.PublicKey) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
@@ -129,6 +138,7 @@ func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, [
|
||||
payments := make([]domain.Payment, 0, num)
|
||||
boardingInputs := make([]ports.BoardingInput, 0)
|
||||
cosigners := make([]*secp256k1.PublicKey, 0, num)
|
||||
descriptors := make(map[domain.VtxoKey]string)
|
||||
for _, p := range paymentsByTime[:num] {
|
||||
boardingInputs = append(boardingInputs, p.boardingInputs...)
|
||||
payments = append(payments, p.Payment)
|
||||
@@ -136,9 +146,15 @@ func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, [
|
||||
cosigners = append(cosigners, pubkey)
|
||||
delete(m.ephemeralKeys, p.Payment.Id)
|
||||
}
|
||||
for _, input := range payments {
|
||||
for _, vtxo := range input.Inputs {
|
||||
descriptors[vtxo.VtxoKey] = m.descriptors[vtxo.VtxoKey]
|
||||
delete(m.descriptors, vtxo.VtxoKey)
|
||||
}
|
||||
}
|
||||
delete(m.payments, p.Id)
|
||||
}
|
||||
return payments, boardingInputs, cosigners
|
||||
return payments, boardingInputs, descriptors, cosigners
|
||||
}
|
||||
|
||||
func (m *paymentsMap) update(payment domain.Payment) error {
|
||||
|
||||
Reference in New Issue
Block a user