mirror of
https://github.com/aljazceru/ark.git
synced 2026-01-06 21:44:20 +01:00
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:
@@ -5,7 +5,7 @@ go 1.21.0
|
||||
replace github.com/ark-network/ark/common => ../common
|
||||
|
||||
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/dgraph-io/badger/v4 v4.1.0
|
||||
github.com/go-co-op/gocron v1.36.0
|
||||
@@ -18,7 +18,7 @@ require (
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/timshannon/badgerhold/v4 v4.0.3
|
||||
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/grpc v1.59.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
|
||||
@@ -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/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/go-elements v0.5.1 h1:F83n7dScOnAnpyH9VgWLdC68Qcva+2EWVzzNuW2UKak=
|
||||
github.com/vulpemventures/go-elements v0.5.1/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU=
|
||||
github.com/vulpemventures/go-elements v0.5.2 h1:vIDzVpRXG5PnlzHA8tCnr2Tn7raIV5cHy7bRyDrbuM4=
|
||||
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/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/ark-network/ark/internal/core/domain"
|
||||
"github.com/ark-network/ark/internal/core/ports"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulpemventures/go-elements/network"
|
||||
@@ -62,7 +63,9 @@ func NewService(
|
||||
) (Service, error) {
|
||||
eventsCh := make(chan domain.RoundEvent)
|
||||
paymentRequests := newPaymentsMap(nil)
|
||||
forfeitTxs := newForfeitTxsMap()
|
||||
|
||||
genesisHash, _ := chainhash.NewHashFromStr(onchainNetwork.GenesisBlockHash)
|
||||
forfeitTxs := newForfeitTxsMap(genesisHash)
|
||||
pubkey, err := walletSvc.GetPubkey(context.Background())
|
||||
if err != nil {
|
||||
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 {
|
||||
if err := s.forfeitTxs.sign(forfeitTxs); err != nil {
|
||||
return fmt.Errorf("invalid forfeit tx: %s", err)
|
||||
}
|
||||
return nil
|
||||
return s.forfeitTxs.sign(forfeitTxs)
|
||||
}
|
||||
|
||||
func (s *service) ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, error) {
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ark-network/ark/common"
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -136,22 +141,36 @@ type signedTx struct {
|
||||
}
|
||||
|
||||
type forfeitTxsMap struct {
|
||||
lock *sync.RWMutex
|
||||
forfeitTxs map[string]*signedTx
|
||||
lock *sync.RWMutex
|
||||
forfeitTxs map[string]*signedTx
|
||||
genesisBlockHash *chainhash.Hash
|
||||
}
|
||||
|
||||
func newForfeitTxsMap() *forfeitTxsMap {
|
||||
return &forfeitTxsMap{&sync.RWMutex{}, make(map[string]*signedTx)}
|
||||
func newForfeitTxsMap(genesisBlockHash *chainhash.Hash) *forfeitTxsMap {
|
||||
return &forfeitTxsMap{&sync.RWMutex{}, make(map[string]*signedTx), genesisBlockHash}
|
||||
}
|
||||
|
||||
func (m *forfeitTxsMap) push(txs []string) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
faucetTxID, _ := hex.DecodeString(faucetVtxo.Txid)
|
||||
|
||||
for _, tx := range txs {
|
||||
ptx, _ := psetv2.NewPsetFromBase64(tx)
|
||||
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()
|
||||
|
||||
for _, tx := range txs {
|
||||
ptx, err := psetv2.NewPsetFromBase64(tx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid forfeit tx format")
|
||||
}
|
||||
ptx, _ := psetv2.NewPsetFromBase64(tx)
|
||||
utx, _ := ptx.UnsignedTx()
|
||||
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
|
||||
} else {
|
||||
return fmt.Errorf("invalid signature")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m.forfeitTxs[txid].signed = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/ark-network/ark/internal/core/domain"
|
||||
"github.com/ark-network/ark/internal/core/ports"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/vulpemventures/go-elements/address"
|
||||
"github.com/vulpemventures/go-elements/elementsutil"
|
||||
"github.com/vulpemventures/go-elements/network"
|
||||
"github.com/vulpemventures/go-elements/payment"
|
||||
"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) {
|
||||
unspendableKeyBytes, _ := hex.DecodeString(unspendablePoint)
|
||||
unspendableKey, _ := secp256k1.ParsePubKey(unspendableKeyBytes)
|
||||
|
||||
sweepTaprootLeaf, err := sweepTapLeaf(aspPubkey)
|
||||
outputScript, _, err := b.getLeafTaprootTree(userPubkey, aspPubkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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)
|
||||
return outputScript, nil
|
||||
}
|
||||
|
||||
// BuildForfeitTxs implements ports.TxBuilder.
|
||||
@@ -119,17 +103,46 @@ func (b *txBuilder) BuildForfeitTxs(
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
lbtc, _ := elementsutil.AssetHashToBytes(b.net.AssetID)
|
||||
|
||||
forfeitTxs = make([]string, 0)
|
||||
|
||||
for _, payment := range payments {
|
||||
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 {
|
||||
forfeitTx, err := createForfeitTx(
|
||||
connector,
|
||||
connector.input,
|
||||
connector.witnessUtxo,
|
||||
psetv2.InputArgs{
|
||||
Txid: vtxo.Txid,
|
||||
TxIndex: vtxo.VOut,
|
||||
},
|
||||
vtxo.Amount,
|
||||
&transaction.TxOutput{
|
||||
Asset: lbtc,
|
||||
Value: vtxoAmount,
|
||||
Script: vtxoOutputScript,
|
||||
},
|
||||
vtxoTaprootTree,
|
||||
aspScript,
|
||||
*b.net,
|
||||
)
|
||||
@@ -140,6 +153,7 @@ func (b *txBuilder) BuildForfeitTxs(
|
||||
forfeitTxs = append(forfeitTxs, forfeitTx)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return connectors, forfeitTxs, nil
|
||||
@@ -211,45 +225,79 @@ func (b *txBuilder) BuildPoolTx(
|
||||
return
|
||||
}
|
||||
|
||||
func connectorsToInputArgs(connectors []string) ([]psetv2.InputArgs, error) {
|
||||
inputs := make([]psetv2.InputArgs, 0, len(connectors)+1)
|
||||
func (b *txBuilder) getLeafTaprootTree(userPubkey, aspPubkey *secp256k1.PublicKey) ([]byte, *taproot.IndexedElementsTapScriptTree, error) {
|
||||
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 {
|
||||
txID, err := getTxID(psetb64)
|
||||
pset, err := psetv2.NewPsetFromBase64(psetb64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
utx, err := pset.UnsignedTx()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txID := utx.TxHash().String()
|
||||
|
||||
input := psetv2.InputArgs{
|
||||
Txid: txID,
|
||||
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{
|
||||
Txid: txID,
|
||||
TxIndex: 1,
|
||||
}
|
||||
inputs = append(inputs, input)
|
||||
inputs = append(inputs, inputWithWitnessUtxo{
|
||||
input: input,
|
||||
witnessUtxo: utx.Outputs[1],
|
||||
})
|
||||
}
|
||||
}
|
||||
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 {
|
||||
var sum uint64
|
||||
for _, payment := range payments {
|
||||
|
||||
@@ -300,14 +300,14 @@ func TestBuildCongestionTree(t *testing.T) {
|
||||
func TestBuildForfeitTxs(t *testing.T) {
|
||||
builder := txbuilder.NewTxBuilder(network.Liquid)
|
||||
|
||||
// TODO
|
||||
poolTx, err := createTestPoolTx(1000, 2)
|
||||
// TODO: replace with fixture.
|
||||
poolTxHex, err := createTestPoolTx(1000, 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, err := transaction.NewTxFromHex(poolTx)
|
||||
poolTx, err := transaction.NewTxFromHex(poolTxHex)
|
||||
require.NoError(t, err)
|
||||
|
||||
poolTxID := tx.TxHash().String()
|
||||
poolTxid := poolTx.TxHash().String()
|
||||
|
||||
fixtures := []struct {
|
||||
payments []domain.Payment
|
||||
@@ -363,7 +363,7 @@ func TestBuildForfeitTxs(t *testing.T) {
|
||||
|
||||
for _, f := range fixtures {
|
||||
connectors, forfeitTxs, err := builder.BuildForfeitTxs(
|
||||
key, poolTx, f.payments,
|
||||
key, poolTxHex, f.payments,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
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.Outputs, 2)
|
||||
|
||||
expectedInputTxid := poolTxID
|
||||
expectedInputTxid := poolTxid
|
||||
expectedInputVout := uint32(1)
|
||||
if i > 0 {
|
||||
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
|
||||
for _, pset := range forfeitTxsPsets {
|
||||
require.Len(t, pset.Inputs, 2)
|
||||
require.Len(t, pset.Outputs, 1)
|
||||
require.Len(t, pset.Outputs, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
package txbuilder
|
||||
|
||||
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/psetv2"
|
||||
"github.com/vulpemventures/go-elements/taproot"
|
||||
"github.com/vulpemventures/go-elements/transaction"
|
||||
)
|
||||
|
||||
func createForfeitTx(
|
||||
connectorInput psetv2.InputArgs,
|
||||
connectorWitnessUtxo *transaction.TxOutput,
|
||||
vtxoInput psetv2.InputArgs,
|
||||
vtxoAmount uint64,
|
||||
vtxoWitnessUtxo *transaction.TxOutput,
|
||||
vtxoTaprootTree *taproot.IndexedElementsTapScriptTree,
|
||||
aspScript []byte,
|
||||
net network.Network,
|
||||
) (forfeitTx string, err error) {
|
||||
@@ -22,7 +31,42 @@ func createForfeitTx(
|
||||
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 {
|
||||
return "", err
|
||||
}
|
||||
@@ -30,9 +74,13 @@ func createForfeitTx(
|
||||
err = updater.AddOutputs([]psetv2.OutputArgs{
|
||||
{
|
||||
Asset: net.AssetID,
|
||||
Amount: vtxoAmount,
|
||||
Amount: vtxoAmount + connectorAmount - 30,
|
||||
Script: aspScript,
|
||||
},
|
||||
{
|
||||
Asset: net.AssetID,
|
||||
Amount: 30,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -18,7 +18,7 @@ func parseTxs(txs []string) ([]string, error) {
|
||||
}
|
||||
for _, tx := range txs {
|
||||
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
|
||||
|
||||
@@ -6,14 +6,16 @@ require (
|
||||
github.com/btcsuite/btcd v0.23.1
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2
|
||||
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/stretchr/testify v1.8.0
|
||||
)
|
||||
|
||||
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/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/sys v0.0.0-20220608164250-635b8c9b7f68 // indirect
|
||||
)
|
||||
@@ -21,6 +23,6 @@ require (
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // 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
|
||||
)
|
||||
|
||||
@@ -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/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/go-elements v0.5.1 h1:F83n7dScOnAnpyH9VgWLdC68Qcva+2EWVzzNuW2UKak=
|
||||
github.com/vulpemventures/go-elements v0.5.1/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU=
|
||||
github.com/vulpemventures/go-elements v0.5.2 h1:vIDzVpRXG5PnlzHA8tCnr2Tn7raIV5cHy7bRyDrbuM4=
|
||||
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/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
||||
48
common/taproot.go
Normal file
48
common/taproot.go
Normal 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
|
||||
}
|
||||
126
noah/common.go
126
noah/common.go
@@ -9,13 +9,16 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/vulpemventures/go-elements/network"
|
||||
"github.com/vulpemventures/go-elements/payment"
|
||||
"github.com/vulpemventures/go-elements/psetv2"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
@@ -85,6 +88,7 @@ func privateKeyFromPassword() (*secp256k1.PrivateKey, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("key unlocked")
|
||||
|
||||
cypher := NewAES128Cypher()
|
||||
privateKeyBytes, err := cypher.Decrypt(encryptedPrivateKey, password)
|
||||
@@ -333,3 +337,125 @@ func printJSON(resp interface{}) error {
|
||||
fmt.Println(string(jsonBytes))
|
||||
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
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ replace github.com/ark-network/ark => ../asp
|
||||
|
||||
require (
|
||||
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/btcec/v2 v2.3.2
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3
|
||||
@@ -31,7 +31,7 @@ require (
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // 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
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
|
||||
@@ -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/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/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/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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/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/go-elements v0.5.1 h1:F83n7dScOnAnpyH9VgWLdC68Qcva+2EWVzzNuW2UKak=
|
||||
github.com/vulpemventures/go-elements v0.5.1/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU=
|
||||
github.com/vulpemventures/go-elements v0.5.2 h1:vIDzVpRXG5PnlzHA8tCnr2Tn7raIV5cHy7bRyDrbuM4=
|
||||
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/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
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/vulpemventures/go-elements/address"
|
||||
"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{
|
||||
Inputs: inputs,
|
||||
})
|
||||
@@ -147,81 +150,21 @@ func collaborativeRedeem(ctx *cli.Context, addr string, amount uint64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
stream, err := client.GetEventStream(ctx.Context, &arkv1.GetEventStreamRequest{})
|
||||
poolTxID, err := handleRoundStream(
|
||||
ctx,
|
||||
client,
|
||||
registerResponse.GetId(),
|
||||
selectedCoins,
|
||||
secKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pingStop func()
|
||||
pingReq := &arkv1.PingRequest{
|
||||
PaymentId: registerResponse.GetId(),
|
||||
}
|
||||
for pingStop == nil {
|
||||
pingStop = ping(ctx, client, pingReq)
|
||||
}
|
||||
|
||||
for {
|
||||
event, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
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(),
|
||||
})
|
||||
}
|
||||
if err := printJSON(map[string]interface{}{
|
||||
"pool_txid": poolTxID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
111
noah/send.go
111
noah/send.go
@@ -4,14 +4,10 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/vulpemventures/go-elements/psetv2"
|
||||
)
|
||||
|
||||
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{
|
||||
Inputs: inputs,
|
||||
})
|
||||
@@ -148,102 +149,22 @@ func sendAction(ctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
stream, err := client.GetEventStream(ctx.Context, &arkv1.GetEventStreamRequest{})
|
||||
poolTxID, err := handleRoundStream(
|
||||
ctx,
|
||||
client,
|
||||
registerResponse.GetId(),
|
||||
selectedCoins,
|
||||
secKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pingStop func()
|
||||
pingReq := &arkv1.PingRequest{
|
||||
PaymentId: registerResponse.GetId(),
|
||||
}
|
||||
for pingStop == nil {
|
||||
pingStop = ping(ctx, client, pingReq)
|
||||
}
|
||||
|
||||
for {
|
||||
event, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
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(),
|
||||
})
|
||||
}
|
||||
if err := printJSON(map[string]interface{}{
|
||||
"pool_txid": poolTxID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -125,10 +125,7 @@ func signPset(
|
||||
continue
|
||||
}
|
||||
|
||||
pubkey, err := getWalletPublicKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pubkey := prvKey.PubKey()
|
||||
|
||||
vtxoLeaf, err := common.VtxoScript(pubkey)
|
||||
if err != nil {
|
||||
@@ -174,8 +171,6 @@ func signPset(
|
||||
if err := signer.SignTaprootInputTapscriptSig(i, tapScriptSig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user