Forfeit transactions: signing process (#81)

* sign forfeit transactions

* revert txid + move SignVtxos func

* Fix nolint

* Fix

* fix connectorsToInputArgs function

---------

Co-authored-by: altafan <18440657+altafan@users.noreply.github.com>
This commit is contained in:
Louis Singer
2024-01-18 17:17:23 +01:00
committed by GitHub
parent f037622b91
commit 3407fd277a
17 changed files with 439 additions and 258 deletions

View File

@@ -5,7 +5,7 @@ go 1.21.0
replace github.com/ark-network/ark/common => ../common replace github.com/ark-network/ark/common => ../common
require ( require (
github.com/ark-network/ark/common v0.0.0-00010101000000-000000000000 github.com/ark-network/ark/common v0.0.0
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0
github.com/dgraph-io/badger/v4 v4.1.0 github.com/dgraph-io/badger/v4 v4.1.0
github.com/go-co-op/gocron v1.36.0 github.com/go-co-op/gocron v1.36.0
@@ -18,7 +18,7 @@ require (
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/timshannon/badgerhold/v4 v4.0.3 github.com/timshannon/badgerhold/v4 v4.0.3
github.com/urfave/cli/v2 v2.26.0 github.com/urfave/cli/v2 v2.26.0
github.com/vulpemventures/go-elements v0.5.1 github.com/vulpemventures/go-elements v0.5.2
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17
google.golang.org/grpc v1.59.0 google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0

View File

@@ -327,8 +327,8 @@ github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 h1:CTcw80hz/Sw8hqlKX5ZYvBUF5gAHSHwdjXxRf/cjDcI= github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 h1:CTcw80hz/Sw8hqlKX5ZYvBUF5gAHSHwdjXxRf/cjDcI=
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:GXBJykxW2kUcktGdsgyay7uwwWvkljASfljNcT0mbh8= github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:GXBJykxW2kUcktGdsgyay7uwwWvkljASfljNcT0mbh8=
github.com/vulpemventures/go-elements v0.5.1 h1:F83n7dScOnAnpyH9VgWLdC68Qcva+2EWVzzNuW2UKak= github.com/vulpemventures/go-elements v0.5.2 h1:vIDzVpRXG5PnlzHA8tCnr2Tn7raIV5cHy7bRyDrbuM4=
github.com/vulpemventures/go-elements v0.5.1/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU= github.com/vulpemventures/go-elements v0.5.2/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU=
github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCzlAjYFGLiLiOdq7Xo= github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCzlAjYFGLiLiOdq7Xo=
github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM= github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=

View File

@@ -10,6 +10,7 @@ import (
"github.com/ark-network/ark/common" "github.com/ark-network/ark/common"
"github.com/ark-network/ark/internal/core/domain" "github.com/ark-network/ark/internal/core/domain"
"github.com/ark-network/ark/internal/core/ports" "github.com/ark-network/ark/internal/core/ports"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/network"
@@ -62,7 +63,9 @@ func NewService(
) (Service, error) { ) (Service, error) {
eventsCh := make(chan domain.RoundEvent) eventsCh := make(chan domain.RoundEvent)
paymentRequests := newPaymentsMap(nil) paymentRequests := newPaymentsMap(nil)
forfeitTxs := newForfeitTxsMap()
genesisHash, _ := chainhash.NewHashFromStr(onchainNetwork.GenesisBlockHash)
forfeitTxs := newForfeitTxsMap(genesisHash)
pubkey, err := walletSvc.GetPubkey(context.Background()) pubkey, err := walletSvc.GetPubkey(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch pubkey: %s", err) return nil, fmt.Errorf("failed to fetch pubkey: %s", err)
@@ -169,10 +172,7 @@ func (s *service) FaucetVtxos(ctx context.Context, userPubkey *secp256k1.PublicK
} }
func (s *service) SignVtxos(ctx context.Context, forfeitTxs []string) error { func (s *service) SignVtxos(ctx context.Context, forfeitTxs []string) error {
if err := s.forfeitTxs.sign(forfeitTxs); err != nil { return s.forfeitTxs.sign(forfeitTxs)
return fmt.Errorf("invalid forfeit tx: %s", err)
}
return nil
} }
func (s *service) ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, error) { func (s *service) ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, error) {

View File

@@ -1,12 +1,17 @@
package application package application
import ( import (
"bytes"
"encoding/hex"
"fmt" "fmt"
"sort" "sort"
"sync" "sync"
"time" "time"
"github.com/ark-network/ark/common"
"github.com/ark-network/ark/internal/core/domain" "github.com/ark-network/ark/internal/core/domain"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/vulpemventures/go-elements/psetv2" "github.com/vulpemventures/go-elements/psetv2"
) )
@@ -138,20 +143,34 @@ type signedTx struct {
type forfeitTxsMap struct { type forfeitTxsMap struct {
lock *sync.RWMutex lock *sync.RWMutex
forfeitTxs map[string]*signedTx forfeitTxs map[string]*signedTx
genesisBlockHash *chainhash.Hash
} }
func newForfeitTxsMap() *forfeitTxsMap { func newForfeitTxsMap(genesisBlockHash *chainhash.Hash) *forfeitTxsMap {
return &forfeitTxsMap{&sync.RWMutex{}, make(map[string]*signedTx)} return &forfeitTxsMap{&sync.RWMutex{}, make(map[string]*signedTx), genesisBlockHash}
} }
func (m *forfeitTxsMap) push(txs []string) { func (m *forfeitTxsMap) push(txs []string) {
m.lock.Lock() m.lock.Lock()
defer m.lock.Unlock() defer m.lock.Unlock()
faucetTxID, _ := hex.DecodeString(faucetVtxo.Txid)
for _, tx := range txs { for _, tx := range txs {
ptx, _ := psetv2.NewPsetFromBase64(tx) ptx, _ := psetv2.NewPsetFromBase64(tx)
utx, _ := ptx.UnsignedTx() utx, _ := ptx.UnsignedTx()
m.forfeitTxs[utx.TxHash().String()] = &signedTx{tx, false}
signed := false
// find the faucet vtxos, and mark them as signed
for _, input := range ptx.Inputs {
if bytes.Equal(input.PreviousTxid, faucetTxID) {
signed = true
break
}
}
m.forfeitTxs[utx.TxHash().String()] = &signedTx{tx, signed}
} }
} }
@@ -160,17 +179,50 @@ func (m *forfeitTxsMap) sign(txs []string) error {
defer m.lock.Unlock() defer m.lock.Unlock()
for _, tx := range txs { for _, tx := range txs {
ptx, err := psetv2.NewPsetFromBase64(tx) ptx, _ := psetv2.NewPsetFromBase64(tx)
if err != nil {
return fmt.Errorf("invalid forfeit tx format")
}
utx, _ := ptx.UnsignedTx() utx, _ := ptx.UnsignedTx()
txid := utx.TxHash().String() txid := utx.TxHash().String()
if _, ok := m.forfeitTxs[txid]; !ok {
return fmt.Errorf("forfeit tx %s not found", txid) if _, ok := m.forfeitTxs[txid]; ok {
for index, input := range ptx.Inputs {
if len(input.TapScriptSig) > 0 {
for _, tapScriptSig := range input.TapScriptSig {
leafHash, err := chainhash.NewHash(tapScriptSig.LeafHash)
if err != nil {
return err
} }
preimage, err := common.TaprootPreimage(
m.genesisBlockHash,
ptx,
index,
leafHash,
)
if err != nil {
return err
}
sig, err := schnorr.ParseSignature(tapScriptSig.Signature)
if err != nil {
return err
}
pubkey, err := schnorr.ParsePubKey(tapScriptSig.PubKey)
if err != nil {
return err
}
if sig.Verify(preimage, pubkey) {
m.forfeitTxs[txid].signed = true m.forfeitTxs[txid].signed = true
} else {
return fmt.Errorf("invalid signature")
} }
}
}
}
}
}
return nil return nil
} }

View File

@@ -4,10 +4,12 @@ import (
"context" "context"
"encoding/hex" "encoding/hex"
"github.com/ark-network/ark/common"
"github.com/ark-network/ark/internal/core/domain" "github.com/ark-network/ark/internal/core/domain"
"github.com/ark-network/ark/internal/core/ports" "github.com/ark-network/ark/internal/core/ports"
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/vulpemventures/go-elements/address" "github.com/vulpemventures/go-elements/address"
"github.com/vulpemventures/go-elements/elementsutil"
"github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/network"
"github.com/vulpemventures/go-elements/payment" "github.com/vulpemventures/go-elements/payment"
"github.com/vulpemventures/go-elements/psetv2" "github.com/vulpemventures/go-elements/psetv2"
@@ -58,29 +60,11 @@ func getTxid(txStr string) (string, error) {
} }
func (b *txBuilder) GetLeafOutputScript(userPubkey, aspPubkey *secp256k1.PublicKey) ([]byte, error) { func (b *txBuilder) GetLeafOutputScript(userPubkey, aspPubkey *secp256k1.PublicKey) ([]byte, error) {
unspendableKeyBytes, _ := hex.DecodeString(unspendablePoint) outputScript, _, err := b.getLeafTaprootTree(userPubkey, aspPubkey)
unspendableKey, _ := secp256k1.ParsePubKey(unspendableKeyBytes)
sweepTaprootLeaf, err := sweepTapLeaf(aspPubkey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return outputScript, nil
leafScript, err := checksigScript(userPubkey)
if err != nil {
return nil, err
}
leafTaprootLeaf := taproot.NewBaseTapElementsLeaf(leafScript)
leafTaprootTree := taproot.AssembleTaprootScriptTree(leafTaprootLeaf, *sweepTaprootLeaf)
root := leafTaprootTree.RootNode.TapHash()
taprootKey := taproot.ComputeTaprootOutputKey(
unspendableKey,
root[:],
)
return taprootOutputScript(taprootKey)
} }
// BuildForfeitTxs implements ports.TxBuilder. // BuildForfeitTxs implements ports.TxBuilder.
@@ -119,17 +103,46 @@ func (b *txBuilder) BuildForfeitTxs(
return nil, nil, err return nil, nil, err
} }
lbtc, _ := elementsutil.AssetHashToBytes(b.net.AssetID)
forfeitTxs = make([]string, 0) forfeitTxs = make([]string, 0)
for _, payment := range payments { for _, payment := range payments {
for _, vtxo := range payment.Inputs { for _, vtxo := range payment.Inputs {
vtxoAmount, err := elementsutil.ValueToBytes(vtxo.Amount)
if err != nil {
return nil, nil, err
}
pubkeyBytes, err := hex.DecodeString(vtxo.Pubkey)
if err != nil {
return nil, nil, err
}
vtxoPubkey, err := secp256k1.ParsePubKey(pubkeyBytes)
if err != nil {
return nil, nil, err
}
vtxoOutputScript, vtxoTaprootTree, err := b.getLeafTaprootTree(vtxoPubkey, aspPubkey)
if err != nil {
return nil, nil, err
}
for _, connector := range connectorsAsInputs { for _, connector := range connectorsAsInputs {
forfeitTx, err := createForfeitTx( forfeitTx, err := createForfeitTx(
connector, connector.input,
connector.witnessUtxo,
psetv2.InputArgs{ psetv2.InputArgs{
Txid: vtxo.Txid, Txid: vtxo.Txid,
TxIndex: vtxo.VOut, TxIndex: vtxo.VOut,
}, },
vtxo.Amount, &transaction.TxOutput{
Asset: lbtc,
Value: vtxoAmount,
Script: vtxoOutputScript,
},
vtxoTaprootTree,
aspScript, aspScript,
*b.net, *b.net,
) )
@@ -140,6 +153,7 @@ func (b *txBuilder) BuildForfeitTxs(
forfeitTxs = append(forfeitTxs, forfeitTx) forfeitTxs = append(forfeitTxs, forfeitTx)
} }
} }
} }
return connectors, forfeitTxs, nil return connectors, forfeitTxs, nil
@@ -211,45 +225,79 @@ func (b *txBuilder) BuildPoolTx(
return return
} }
func connectorsToInputArgs(connectors []string) ([]psetv2.InputArgs, error) { func (b *txBuilder) getLeafTaprootTree(userPubkey, aspPubkey *secp256k1.PublicKey) ([]byte, *taproot.IndexedElementsTapScriptTree, error) {
inputs := make([]psetv2.InputArgs, 0, len(connectors)+1) sweepTaprootLeaf, err := sweepTapLeaf(aspPubkey)
if err != nil {
return nil, nil, err
}
vtxoLeaf, err := common.VtxoScript(userPubkey)
if err != nil {
return nil, nil, err
}
leafTaprootTree := taproot.AssembleTaprootScriptTree(*vtxoLeaf, *sweepTaprootLeaf)
root := leafTaprootTree.RootNode.TapHash()
unspendableKeyBytes, _ := hex.DecodeString(unspendablePoint)
unspendableKey, _ := secp256k1.ParsePubKey(unspendableKeyBytes)
taprootKey := taproot.ComputeTaprootOutputKey(
unspendableKey,
root[:],
)
outputScript, err := taprootOutputScript(taprootKey)
if err != nil {
return nil, nil, err
}
return outputScript, leafTaprootTree, nil
}
type inputWithWitnessUtxo struct {
input psetv2.InputArgs
witnessUtxo *transaction.TxOutput
}
func connectorsToInputArgs(connectors []string) ([]inputWithWitnessUtxo, error) {
inputs := make([]inputWithWitnessUtxo, 0, len(connectors)+1)
for i, psetb64 := range connectors { for i, psetb64 := range connectors {
txID, err := getTxID(psetb64) pset, err := psetv2.NewPsetFromBase64(psetb64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
utx, err := pset.UnsignedTx()
if err != nil {
return nil, err
}
txID := utx.TxHash().String()
input := psetv2.InputArgs{ input := psetv2.InputArgs{
Txid: txID, Txid: txID,
TxIndex: 0, TxIndex: 0,
} }
inputs = append(inputs, input) inputs = append(inputs, inputWithWitnessUtxo{
input: input,
witnessUtxo: utx.Outputs[0],
})
if i == len(connectors)-1 { if i == len(connectors)-1 && len(utx.Outputs) > 1 {
input := psetv2.InputArgs{ input := psetv2.InputArgs{
Txid: txID, Txid: txID,
TxIndex: 1, TxIndex: 1,
} }
inputs = append(inputs, input) inputs = append(inputs, inputWithWitnessUtxo{
input: input,
witnessUtxo: utx.Outputs[1],
})
} }
} }
return inputs, nil return inputs, nil
} }
func getTxID(psetBase64 string) (string, error) {
pset, err := psetv2.NewPsetFromBase64(psetBase64)
if err != nil {
return "", err
}
utx, err := pset.UnsignedTx()
if err != nil {
return "", err
}
return utx.TxHash().String(), nil
}
func numberOfVTXOs(payments []domain.Payment) uint64 { func numberOfVTXOs(payments []domain.Payment) uint64 {
var sum uint64 var sum uint64
for _, payment := range payments { for _, payment := range payments {

View File

@@ -300,14 +300,14 @@ func TestBuildCongestionTree(t *testing.T) {
func TestBuildForfeitTxs(t *testing.T) { func TestBuildForfeitTxs(t *testing.T) {
builder := txbuilder.NewTxBuilder(network.Liquid) builder := txbuilder.NewTxBuilder(network.Liquid)
// TODO // TODO: replace with fixture.
poolTx, err := createTestPoolTx(1000, 2) poolTxHex, err := createTestPoolTx(1000, 2)
require.NoError(t, err) require.NoError(t, err)
tx, err := transaction.NewTxFromHex(poolTx) poolTx, err := transaction.NewTxFromHex(poolTxHex)
require.NoError(t, err) require.NoError(t, err)
poolTxID := tx.TxHash().String() poolTxid := poolTx.TxHash().String()
fixtures := []struct { fixtures := []struct {
payments []domain.Payment payments []domain.Payment
@@ -363,7 +363,7 @@ func TestBuildForfeitTxs(t *testing.T) {
for _, f := range fixtures { for _, f := range fixtures {
connectors, forfeitTxs, err := builder.BuildForfeitTxs( connectors, forfeitTxs, err := builder.BuildForfeitTxs(
key, poolTx, f.payments, key, poolTxHex, f.payments,
) )
require.NoError(t, err) require.NoError(t, err)
require.Len(t, connectors, f.expectedNumOfConnectors) require.Len(t, connectors, f.expectedNumOfConnectors)
@@ -381,7 +381,7 @@ func TestBuildForfeitTxs(t *testing.T) {
require.Len(t, pset.Inputs, 1) require.Len(t, pset.Inputs, 1)
require.Len(t, pset.Outputs, 2) require.Len(t, pset.Outputs, 2)
expectedInputTxid := poolTxID expectedInputTxid := poolTxid
expectedInputVout := uint32(1) expectedInputVout := uint32(1)
if i > 0 { if i > 0 {
tx, err := connectorsPsets[i-1].UnsignedTx() tx, err := connectorsPsets[i-1].UnsignedTx()
@@ -406,7 +406,7 @@ func TestBuildForfeitTxs(t *testing.T) {
// each forfeit tx should have 2 inputs and 2 outputs // each forfeit tx should have 2 inputs and 2 outputs
for _, pset := range forfeitTxsPsets { for _, pset := range forfeitTxsPsets {
require.Len(t, pset.Inputs, 2) require.Len(t, pset.Inputs, 2)
require.Len(t, pset.Outputs, 1) require.Len(t, pset.Outputs, 2)
} }
} }
} }

View File

@@ -1,14 +1,23 @@
package txbuilder package txbuilder
import ( import (
"encoding/hex"
"github.com/btcsuite/btcd/txscript"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/vulpemventures/go-elements/elementsutil"
"github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/network"
"github.com/vulpemventures/go-elements/psetv2" "github.com/vulpemventures/go-elements/psetv2"
"github.com/vulpemventures/go-elements/taproot"
"github.com/vulpemventures/go-elements/transaction"
) )
func createForfeitTx( func createForfeitTx(
connectorInput psetv2.InputArgs, connectorInput psetv2.InputArgs,
connectorWitnessUtxo *transaction.TxOutput,
vtxoInput psetv2.InputArgs, vtxoInput psetv2.InputArgs,
vtxoAmount uint64, vtxoWitnessUtxo *transaction.TxOutput,
vtxoTaprootTree *taproot.IndexedElementsTapScriptTree,
aspScript []byte, aspScript []byte,
net network.Network, net network.Network,
) (forfeitTx string, err error) { ) (forfeitTx string, err error) {
@@ -22,7 +31,42 @@ func createForfeitTx(
return "", err return "", err
} }
err = updater.AddInputs([]psetv2.InputArgs{connectorInput, vtxoInput}) if err = updater.AddInputs([]psetv2.InputArgs{connectorInput, vtxoInput}); err != nil {
return "", err
}
if err = updater.AddInWitnessUtxo(0, connectorWitnessUtxo); err != nil {
return "", err
}
if err := updater.AddInSighashType(0, txscript.SigHashAll); err != nil {
return "", err
}
if err = updater.AddInWitnessUtxo(1, vtxoWitnessUtxo); err != nil {
return "", err
}
if err := updater.AddInSighashType(1, txscript.SigHashDefault); err != nil {
return "", err
}
unspendableKeyBytes, _ := hex.DecodeString(unspendablePoint)
unspendableKey, _ := secp256k1.ParsePubKey(unspendableKeyBytes)
for _, proof := range vtxoTaprootTree.LeafMerkleProofs {
tapScript := psetv2.NewTapLeafScript(proof, unspendableKey)
if err := updater.AddInTapLeafScript(1, tapScript); err != nil {
return "", err
}
}
vtxoAmount, err := elementsutil.ValueFromBytes(vtxoWitnessUtxo.Value)
if err != nil {
return "", err
}
connectorAmount, err := elementsutil.ValueFromBytes(connectorWitnessUtxo.Value)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -30,9 +74,13 @@ func createForfeitTx(
err = updater.AddOutputs([]psetv2.OutputArgs{ err = updater.AddOutputs([]psetv2.OutputArgs{
{ {
Asset: net.AssetID, Asset: net.AssetID,
Amount: vtxoAmount, Amount: vtxoAmount + connectorAmount - 30,
Script: aspScript, Script: aspScript,
}, },
{
Asset: net.AssetID,
Amount: 30,
},
}) })
if err != nil { if err != nil {
return "", err return "", err

View File

@@ -18,7 +18,7 @@ func parseTxs(txs []string) ([]string, error) {
} }
for _, tx := range txs { for _, tx := range txs {
if _, err := psetv2.NewPsetFromBase64(tx); err != nil { if _, err := psetv2.NewPsetFromBase64(tx); err != nil {
return nil, fmt.Errorf("invalid tx format") return nil, fmt.Errorf("invalid tx format %s", err)
} }
} }
return txs, nil return txs, nil

View File

@@ -6,14 +6,16 @@ require (
github.com/btcsuite/btcd v0.23.1 github.com/btcsuite/btcd v0.23.1
github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/btcsuite/btcd/btcec/v2 v2.3.2
github.com/btcsuite/btcd/btcutil v1.1.3 github.com/btcsuite/btcd/btcutil v1.1.3
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
) )
require ( require (
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/btcsuite/btcd/btcutil/psbt v1.1.4 // indirect
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 // indirect golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 // indirect
) )
@@ -21,6 +23,6 @@ require (
require ( require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/vulpemventures/go-elements v0.5.1 github.com/vulpemventures/go-elements v0.5.2
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

View File

@@ -76,8 +76,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 h1:CTcw80hz/Sw8hqlKX5ZYvBUF5gAHSHwdjXxRf/cjDcI= github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 h1:CTcw80hz/Sw8hqlKX5ZYvBUF5gAHSHwdjXxRf/cjDcI=
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:GXBJykxW2kUcktGdsgyay7uwwWvkljASfljNcT0mbh8= github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:GXBJykxW2kUcktGdsgyay7uwwWvkljASfljNcT0mbh8=
github.com/vulpemventures/go-elements v0.5.1 h1:F83n7dScOnAnpyH9VgWLdC68Qcva+2EWVzzNuW2UKak= github.com/vulpemventures/go-elements v0.5.2 h1:vIDzVpRXG5PnlzHA8tCnr2Tn7raIV5cHy7bRyDrbuM4=
github.com/vulpemventures/go-elements v0.5.1/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU= github.com/vulpemventures/go-elements v0.5.2/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU=
github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCzlAjYFGLiLiOdq7Xo= github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCzlAjYFGLiLiOdq7Xo=
github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM= github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

48
common/taproot.go Normal file
View File

@@ -0,0 +1,48 @@
package common
import (
"fmt"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/vulpemventures/go-elements/psetv2"
)
// TaprootPreimage computes the hash for witness v1 input of a pset
// it implicitly assumes that the pset has witnessUtxo fields populated
func TaprootPreimage(
genesisBlockHash *chainhash.Hash,
pset *psetv2.Pset,
inputIndex int,
leafHash *chainhash.Hash,
) ([]byte, error) {
prevoutScripts := make([][]byte, 0)
prevoutAssets := make([][]byte, 0)
prevoutValues := make([][]byte, 0)
for i, input := range pset.Inputs {
if input.WitnessUtxo == nil {
return nil, fmt.Errorf("missing witness utxo on input #%d", i)
}
prevoutScripts = append(prevoutScripts, input.WitnessUtxo.Script)
prevoutAssets = append(prevoutAssets, input.WitnessUtxo.Asset)
prevoutValues = append(prevoutValues, input.WitnessUtxo.Value)
}
utx, err := pset.UnsignedTx()
if err != nil {
return nil, err
}
preimage := utx.HashForWitnessV1(
inputIndex,
prevoutScripts,
prevoutAssets,
prevoutValues,
pset.Inputs[inputIndex].SigHashType,
genesisBlockHash,
leafHash,
nil,
)
return preimage[:], nil
}

View File

@@ -9,13 +9,16 @@ import (
"io" "io"
"net/http" "net/http"
"syscall" "syscall"
"time"
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/ark-network/ark/common" "github.com/ark-network/ark/common"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/network"
"github.com/vulpemventures/go-elements/payment" "github.com/vulpemventures/go-elements/payment"
"github.com/vulpemventures/go-elements/psetv2"
"golang.org/x/term" "golang.org/x/term"
) )
@@ -85,6 +88,7 @@ func privateKeyFromPassword() (*secp256k1.PrivateKey, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
fmt.Println("key unlocked")
cypher := NewAES128Cypher() cypher := NewAES128Cypher()
privateKeyBytes, err := cypher.Decrypt(encryptedPrivateKey, password) privateKeyBytes, err := cypher.Decrypt(encryptedPrivateKey, password)
@@ -333,3 +337,125 @@ func printJSON(resp interface{}) error {
fmt.Println(string(jsonBytes)) fmt.Println(string(jsonBytes))
return nil return nil
} }
func handleRoundStream(
ctx *cli.Context,
client arkv1.ArkServiceClient,
paymentID string,
vtxosToSign []vtxo,
secKey *secp256k1.PrivateKey,
) (poolTxID string, err error) {
stream, err := client.GetEventStream(ctx.Context, &arkv1.GetEventStreamRequest{})
if err != nil {
return "", err
}
var pingStop func()
pingReq := &arkv1.PingRequest{
PaymentId: paymentID,
}
for pingStop == nil {
pingStop = ping(ctx, client, pingReq)
}
defer pingStop()
for {
event, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
return "", err
}
if event.GetRoundFailed() != nil {
pingStop()
return "", fmt.Errorf("round failed: %s", event.GetRoundFailed().GetReason())
}
if event.GetRoundFinalization() != nil {
// stop pinging as soon as we receive some forfeit txs
pingStop()
forfeits := event.GetRoundFinalization().GetForfeitTxs()
signedForfeits := make([]string, 0)
fmt.Println("signing forfeit txs...")
explorer := NewExplorer()
for _, forfeit := range forfeits {
pset, err := psetv2.NewPsetFromBase64(forfeit)
if err != nil {
return "", err
}
for _, input := range pset.Inputs {
inputTxid := chainhash.Hash(input.PreviousTxid).String()
for _, coin := range vtxosToSign {
// check if it contains one of the input to sign
if inputTxid == coin.txid {
if err := signPset(pset, explorer, secKey); err != nil {
return "", err
}
signedPset, err := pset.ToBase64()
if err != nil {
return "", err
}
signedForfeits = append(signedForfeits, signedPset)
}
}
}
}
// if no forfeit txs have been signed, start pinging again and wait for the next round
if len(signedForfeits) == 0 {
fmt.Println("no forfeit txs to sign, waiting for the next round...")
pingStop = nil
for pingStop == nil {
pingStop = ping(ctx, client, pingReq)
}
continue
}
fmt.Printf("%d forfeit txs signed, finalizing payment...\n", len(signedForfeits))
_, err = client.FinalizePayment(ctx.Context, &arkv1.FinalizePaymentRequest{
SignedForfeitTxs: signedForfeits,
})
if err != nil {
return "", err
}
continue
}
if event.GetRoundFinalized() != nil {
return event.GetRoundFinalized().GetPoolTxid(), nil
}
}
return "", fmt.Errorf("stream closed unexpectedly")
}
// send 1 ping message every 5 seconds to signal to the ark service that we are still alive
// returns a function that can be used to stop the pinging
func ping(ctx *cli.Context, client arkv1.ArkServiceClient, req *arkv1.PingRequest) func() {
_, err := client.Ping(ctx.Context, req)
if err != nil {
return nil
}
ticker := time.NewTicker(5 * time.Second)
go func(t *time.Ticker) {
for range t.C {
// nolint
client.Ping(ctx.Context, req)
}
}(ticker)
return ticker.Stop
}

View File

@@ -8,7 +8,7 @@ replace github.com/ark-network/ark => ../asp
require ( require (
github.com/ark-network/ark v0.0.0-00010101000000-000000000000 github.com/ark-network/ark v0.0.0-00010101000000-000000000000
github.com/ark-network/ark/common v0.0.0-00010101000000-000000000000 github.com/ark-network/ark/common v0.0.0
github.com/btcsuite/btcd v0.23.4 github.com/btcsuite/btcd v0.23.4
github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/btcsuite/btcd/btcec/v2 v2.3.2
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3
@@ -31,7 +31,7 @@ require (
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/vulpemventures/go-elements v0.5.1 github.com/vulpemventures/go-elements v0.5.2
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/net v0.19.0 // indirect golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.15.0 // indirect

View File

@@ -82,8 +82,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
@@ -93,8 +91,8 @@ github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 h1:CTcw80hz/Sw8hqlKX5ZYvBUF5gAHSHwdjXxRf/cjDcI= github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 h1:CTcw80hz/Sw8hqlKX5ZYvBUF5gAHSHwdjXxRf/cjDcI=
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:GXBJykxW2kUcktGdsgyay7uwwWvkljASfljNcT0mbh8= github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:GXBJykxW2kUcktGdsgyay7uwwWvkljASfljNcT0mbh8=
github.com/vulpemventures/go-elements v0.5.1 h1:F83n7dScOnAnpyH9VgWLdC68Qcva+2EWVzzNuW2UKak= github.com/vulpemventures/go-elements v0.5.2 h1:vIDzVpRXG5PnlzHA8tCnr2Tn7raIV5cHy7bRyDrbuM4=
github.com/vulpemventures/go-elements v0.5.1/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU= github.com/vulpemventures/go-elements v0.5.2/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU=
github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCzlAjYFGLiLiOdq7Xo= github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCzlAjYFGLiLiOdq7Xo=
github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM= github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=

View File

@@ -3,7 +3,6 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io"
"log" "log"
"math" "math"
"os" "os"
@@ -11,7 +10,6 @@ import (
"time" "time"
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/vulpemventures/go-elements/address" "github.com/vulpemventures/go-elements/address"
"github.com/vulpemventures/go-elements/psetv2" "github.com/vulpemventures/go-elements/psetv2"
@@ -132,6 +130,11 @@ func collaborativeRedeem(ctx *cli.Context, addr string, amount uint64) error {
}) })
} }
secKey, err := privateKeyFromPassword()
if err != nil {
return err
}
registerResponse, err := client.RegisterPayment(ctx.Context, &arkv1.RegisterPaymentRequest{ registerResponse, err := client.RegisterPayment(ctx.Context, &arkv1.RegisterPaymentRequest{
Inputs: inputs, Inputs: inputs,
}) })
@@ -147,83 +150,23 @@ func collaborativeRedeem(ctx *cli.Context, addr string, amount uint64) error {
return err return err
} }
stream, err := client.GetEventStream(ctx.Context, &arkv1.GetEventStreamRequest{}) poolTxID, err := handleRoundStream(
ctx,
client,
registerResponse.GetId(),
selectedCoins,
secKey,
)
if err != nil { if err != nil {
return err return err
} }
var pingStop func() if err := printJSON(map[string]interface{}{
pingReq := &arkv1.PingRequest{ "pool_txid": poolTxID,
PaymentId: registerResponse.GetId(), }); err != nil {
}
for pingStop == nil {
pingStop = ping(ctx, client, pingReq)
}
for {
event, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
return err return err
} }
if event.GetRoundFailed() != nil {
return fmt.Errorf("round failed: %s", event.GetRoundFailed().GetReason())
}
if event.GetRoundFinalization() != nil {
// stop pinging as soon as we receive some forfeit txs
pingStop()
forfeits := event.GetRoundFinalization().GetForfeitTxs()
signedForfeits := make([]string, 0)
for _, forfeit := range forfeits {
pset, err := psetv2.NewPsetFromBase64(forfeit)
if err != nil {
return err
}
// check if it contains one of the input to sign
for _, input := range pset.Inputs {
inputTxid := chainhash.Hash(input.PreviousTxid).String()
for _, coin := range selectedCoins {
if inputTxid == coin.txid {
// TODO: sign the vtxo input
signedForfeits = append(signedForfeits, forfeit)
}
}
}
}
// if no forfeit txs have been signed, start pinging again and wait for the next round
if len(signedForfeits) == 0 {
pingStop = nil
for pingStop == nil {
pingStop = ping(ctx, client, pingReq)
}
continue
}
_, err := client.FinalizePayment(ctx.Context, &arkv1.FinalizePaymentRequest{
SignedForfeitTxs: signedForfeits,
})
if err != nil {
return err
}
continue
}
if event.GetRoundFinalized() != nil {
return printJSON(map[string]interface{}{
"pool_txid": event.GetRoundFinalized().GetPoolTxid(),
})
}
}
return nil return nil
} }

View File

@@ -4,14 +4,10 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"time"
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/ark-network/ark/common" "github.com/ark-network/ark/common"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/vulpemventures/go-elements/psetv2"
) )
type receiver struct { type receiver struct {
@@ -133,6 +129,11 @@ func sendAction(ctx *cli.Context) error {
}) })
} }
secKey, err := privateKeyFromPassword()
if err != nil {
return err
}
registerResponse, err := client.RegisterPayment(ctx.Context, &arkv1.RegisterPaymentRequest{ registerResponse, err := client.RegisterPayment(ctx.Context, &arkv1.RegisterPaymentRequest{
Inputs: inputs, Inputs: inputs,
}) })
@@ -148,102 +149,22 @@ func sendAction(ctx *cli.Context) error {
return err return err
} }
stream, err := client.GetEventStream(ctx.Context, &arkv1.GetEventStreamRequest{}) poolTxID, err := handleRoundStream(
ctx,
client,
registerResponse.GetId(),
selectedCoins,
secKey,
)
if err != nil { if err != nil {
return err return err
} }
var pingStop func() if err := printJSON(map[string]interface{}{
pingReq := &arkv1.PingRequest{ "pool_txid": poolTxID,
PaymentId: registerResponse.GetId(), }); err != nil {
}
for pingStop == nil {
pingStop = ping(ctx, client, pingReq)
}
for {
event, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
return err return err
} }
if event.GetRoundFailed() != nil {
return fmt.Errorf("round failed: %s", event.GetRoundFailed().GetReason())
}
if event.GetRoundFinalization() != nil {
// stop pinging as soon as we receive some forfeit txs
pingStop()
forfeits := event.GetRoundFinalization().GetForfeitTxs()
signedForfeits := make([]string, 0)
for _, forfeit := range forfeits {
pset, err := psetv2.NewPsetFromBase64(forfeit)
if err != nil {
return err
}
// check if it contains one of the input to sign
for _, input := range pset.Inputs {
inputTxid := chainhash.Hash(input.PreviousTxid).String()
for _, coin := range selectedCoins {
if inputTxid == coin.txid {
// TODO: sign the vtxo input
signedForfeits = append(signedForfeits, forfeit)
}
}
}
}
// if no forfeit txs have been signed, start pinging again and wait for the next round
if len(signedForfeits) == 0 {
pingStop = nil
for pingStop == nil {
pingStop = ping(ctx, client, pingReq)
}
continue
}
_, err := client.FinalizePayment(ctx.Context, &arkv1.FinalizePaymentRequest{
SignedForfeitTxs: signedForfeits,
})
if err != nil {
return err
}
continue
}
if event.GetRoundFinalized() != nil {
return printJSON(map[string]interface{}{
"pool_txid": event.GetRoundFinalized().GetPoolTxid(),
})
}
}
return nil return nil
} }
// send 1 ping message every 5 seconds to signal to the ark service that we are still alive
// returns a function that can be used to stop the pinging
func ping(ctx *cli.Context, client arkv1.ArkServiceClient, req *arkv1.PingRequest) func() {
_, err := client.Ping(ctx.Context, req)
if err != nil {
return nil
}
ticker := time.NewTicker(5 * time.Second)
go func(t *time.Ticker) {
for range t.C {
// nolint
client.Ping(ctx.Context, req)
}
}(ticker)
return ticker.Stop
}

View File

@@ -125,10 +125,7 @@ func signPset(
continue continue
} }
pubkey, err := getWalletPublicKey() pubkey := prvKey.PubKey()
if err != nil {
return err
}
vtxoLeaf, err := common.VtxoScript(pubkey) vtxoLeaf, err := common.VtxoScript(pubkey)
if err != nil { if err != nil {
@@ -174,8 +171,6 @@ func signPset(
if err := signer.SignTaprootInputTapscriptSig(i, tapScriptSig); err != nil { if err := signer.SignTaprootInputTapscriptSig(i, tapScriptSig); err != nil {
return err return err
} }
continue
} }
} }
} }