Delay unilateral exit and support send to onchain address (#117)

* add delay on redeem close + forfeit close

* increase default round lifetime (16 minutes min)

* add sequence to final pset

* update CLI and server to support delayed vtxos oncahin

* rename future to "locked"

* add configurable EXIT_DELAY variable

* renaming

* rename "close" --> "closure"

* rename "close" to "closure"

* error message config.go
This commit is contained in:
Louis Singer
2024-02-22 16:47:52 +01:00
committed by GitHub
parent 7c8ee7ab12
commit a95a829b20
30 changed files with 1244 additions and 719 deletions

View File

@@ -38,9 +38,9 @@ func balanceAction(ctx *cli.Context) error {
}
wg := &sync.WaitGroup{}
wg.Add(2)
wg.Add(3)
chRes := make(chan balanceRes, 2)
chRes := make(chan balanceRes, 3)
go func() {
defer wg.Done()
explorer := NewExplorer()
@@ -48,24 +48,37 @@ func balanceAction(ctx *cli.Context) error {
ctx, explorer, client, offchainAddr, withExpiryDetails,
)
if err != nil {
chRes <- balanceRes{0, 0, nil, err}
chRes <- balanceRes{0, 0, nil, nil, err}
return
}
chRes <- balanceRes{balance, 0, amountByExpiration, nil}
chRes <- balanceRes{balance, 0, nil, amountByExpiration, nil}
}()
go func() {
defer wg.Done()
balance, err := getOnchainBalance(onchainAddr)
if err != nil {
chRes <- balanceRes{0, 0, nil, err}
chRes <- balanceRes{0, 0, nil, nil, err}
return
}
chRes <- balanceRes{0, balance, nil, nil}
chRes <- balanceRes{0, balance, nil, nil, nil}
}()
go func() {
defer wg.Done()
availableBalance, futureBalance, err := getOnchainVtxosBalance()
if err != nil {
chRes <- balanceRes{0, 0, nil, nil, err}
return
}
chRes <- balanceRes{0, availableBalance, futureBalance, nil, err}
}()
wg.Wait()
lockedOnchainBalance := []map[string]interface{}{}
details := make([]map[string]interface{}, 0)
offchainBalance, onchainBalance := uint64(0), uint64(0)
nextExpiration := int64(0)
@@ -78,7 +91,7 @@ func balanceAction(ctx *cli.Context) error {
offchainBalance = res.offchainBalance
}
if res.onchainBalance > 0 {
onchainBalance = res.onchainBalance
onchainBalance += res.onchainBalance
}
if res.amountByExpiration != nil {
for timestamp, amount := range res.amountByExpiration {
@@ -96,15 +109,33 @@ func balanceAction(ctx *cli.Context) error {
)
}
}
if res.futureBalance != nil {
for timestamp, amount := range res.futureBalance {
fancyTime := time.Unix(timestamp, 0).Format("2006-01-02 15:04:05")
lockedOnchainBalance = append(
lockedOnchainBalance,
map[string]interface{}{
"spendable_at": fancyTime,
"amount": amount,
},
)
}
}
count++
if count == 2 {
if count == 3 {
break
}
}
response := make(map[string]interface{})
response["onchain_balance"] = onchainBalance
response["onchain_balance"] = map[string]interface{}{
"spendable_amount": onchainBalance,
}
if len(lockedOnchainBalance) > 0 {
response["onchain_balance"].(map[string]interface{})["locked_amount"] = lockedOnchainBalance
}
offchainBalanceJSON := map[string]interface{}{
"total": offchainBalance,
@@ -148,6 +179,7 @@ func balanceAction(ctx *cli.Context) error {
type balanceRes struct {
offchainBalance uint64
onchainBalance uint64
amountByExpiration map[int64]uint64
futureBalance map[int64]uint64 // availableAt -> onchain balance
amountByExpiration map[int64]uint64 // expireAt -> offchain balance
err error
}

View File

@@ -75,7 +75,7 @@ func getClientFromState(ctx *cli.Context) (arkv1.ArkServiceClient, func(), error
if err != nil {
return nil, nil, err
}
addr, ok := state["ark_url"]
addr, ok := state["ark_url"].(string)
if !ok {
return nil, nil, fmt.Errorf("missing ark_url")
}

View File

@@ -15,15 +15,16 @@ import (
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/ark-network/ark/common"
"github.com/ark-network/ark/common/tree"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/urfave/cli/v2"
"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"
"github.com/vulpemventures/go-elements/taproot"
"github.com/vulpemventures/go-elements/transaction"
"golang.org/x/term"
)
@@ -42,7 +43,7 @@ func verifyPassword(password []byte) error {
return err
}
passwordHashString, ok := state["password_hash"]
passwordHashString, ok := state["password_hash"].(string)
if !ok {
return fmt.Errorf("password hash not found")
}
@@ -82,7 +83,7 @@ func privateKeyFromPassword() (*secp256k1.PrivateKey, error) {
return nil, err
}
encryptedPrivateKeyString, ok := state["encrypted_private_key"]
encryptedPrivateKeyString, ok := state["encrypted_private_key"].(string)
if !ok {
return nil, fmt.Errorf("encrypted private key not found")
}
@@ -114,7 +115,7 @@ func getWalletPublicKey() (*secp256k1.PublicKey, error) {
return nil, err
}
publicKeyString, ok := state["public_key"]
publicKeyString, ok := state["public_key"].(string)
if !ok {
return nil, fmt.Errorf("public key not found")
}
@@ -133,7 +134,7 @@ func getServiceProviderPublicKey() (*secp256k1.PublicKey, error) {
return nil, err
}
arkPubKey, ok := state["ark_pubkey"]
arkPubKey, ok := state["ark_pubkey"].(string)
if !ok {
return nil, fmt.Errorf("ark public key not found")
}
@@ -146,6 +147,34 @@ func getServiceProviderPublicKey() (*secp256k1.PublicKey, error) {
return secp256k1.ParsePubKey(pubKeyBytes)
}
func getLifetime() (int64, error) {
state, err := getState()
if err != nil {
return 0, err
}
lifetime, ok := state["ark_lifetime"].(float64)
if !ok {
return 0, fmt.Errorf("lifetime not found")
}
return int64(lifetime), nil
}
func getExitDelay() (int64, error) {
state, err := getState()
if err != nil {
return 0, err
}
exitDelay, ok := state["exit_delay"].(float64)
if !ok {
return 0, fmt.Errorf("exit delay not found")
}
return int64(exitDelay), nil
}
func coinSelect(vtxos []vtxo, amount uint64) ([]vtxo, uint64, error) {
selected := make([]vtxo, 0)
notSelected := make([]vtxo, 0)
@@ -218,6 +247,10 @@ type utxo struct {
Vout uint32 `json:"vout"`
Amount uint64 `json:"value"`
Asset string `json:"asset"`
Status struct {
Confirmed bool `json:"confirmed"`
Blocktime int64 `json:"block_time"`
} `json:"status"`
}
func getOnchainUtxos(addr string) ([]utxo, error) {
@@ -227,6 +260,7 @@ func getOnchainUtxos(addr string) ([]utxo, error) {
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
@@ -260,6 +294,68 @@ func getOnchainBalance(addr string) (uint64, error) {
return balance, nil
}
func getOnchainVtxosBalance() (availableBalance uint64, futureBalance map[int64]uint64, err error) {
userPubKey, err := getWalletPublicKey()
if err != nil {
return
}
aspPublicKey, err := getServiceProviderPublicKey()
if err != nil {
return
}
exitDelay, err := getExitDelay()
if err != nil {
return
}
vtxoTapKey, _, err := computeVtxoTaprootScript(userPubKey, aspPublicKey, uint(exitDelay))
if err != nil {
return
}
_, net := getNetwork()
payment, err := payment.FromTweakedKey(vtxoTapKey, net, nil)
if err != nil {
return
}
addr, err := payment.TaprootAddress()
if err != nil {
return
}
utxos, err := getOnchainUtxos(addr)
if err != nil {
return
}
availableBalance = uint64(0)
futureBalance = make(map[int64]uint64, 0)
now := time.Now()
for _, utxo := range utxos {
blocktime := now
if utxo.Status.Confirmed {
blocktime = time.Unix(utxo.Status.Blocktime, 0)
}
availableAt := blocktime.Add(time.Duration(exitDelay) * time.Second)
if availableAt.After(now) {
if _, ok := futureBalance[availableAt.Unix()]; !ok {
futureBalance[availableAt.Unix()] = 0
}
futureBalance[availableAt.Unix()] += utxo.Amount
} else {
availableBalance += utxo.Amount
}
}
return
}
func getTxBlocktime(txid string) (confirmed bool, blocktime int64, err error) {
_, net := getNetwork()
baseUrl := explorerUrl[net.Name]
@@ -431,7 +527,7 @@ func handleRoundStream(
return "", err
}
_, seconds, err := findSweepClosure(congestionTree)
seconds, err := getLifetime()
if err != nil {
return "", err
}
@@ -446,8 +542,7 @@ func handleRoundStream(
return "", err
}
// validate the receivers
sweepLeaf, err := tree.SweepScript(aspPublicKey, seconds)
exitDelay, err := getExitDelay()
if err != nil {
return "", err
}
@@ -485,16 +580,11 @@ func handleRoundStream(
found := false
// compute the receiver output taproot key
vtxoScript, err := tree.VtxoScript(userPubKey)
outputTapKey, _, err := computeVtxoTaprootScript(userPubKey, aspPublicKey, uint(exitDelay))
if err != nil {
return "", err
}
vtxoTaprootTree := taproot.AssembleTaprootScriptTree(*vtxoScript, *sweepLeaf)
root := vtxoTaprootTree.RootNode.TapHash()
unspendableKey := tree.UnspendableKey()
vtxoTaprootKey := schnorr.SerializePubKey(taproot.ComputeTaprootOutputKey(unspendableKey, root[:]))
leaves := congestionTree.Leaves()
for _, leaf := range leaves {
tx, err := psetv2.NewPsetFromBase64(leaf.Tx)
@@ -506,7 +596,7 @@ func handleRoundStream(
if len(output.Script) == 0 {
continue
}
if bytes.Equal(output.Script[2:], vtxoTaprootKey) {
if bytes.Equal(output.Script[2:], outputTapKey.SerializeCompressed()) {
if output.Value != receiver.Amount {
continue
}
@@ -676,15 +766,15 @@ func findSweepClosure(
}
for _, tapLeaf := range tx.Inputs[0].TapLeafScript {
isSweep, _, lifetime, err := tree.DecodeSweepScript(tapLeaf.Script)
closure := &tree.CSVSigClosure{}
valid, err := closure.Decode(tapLeaf.Script)
if err != nil {
continue
}
if isSweep {
seconds = lifetime
if valid && closure.Seconds > seconds {
seconds = closure.Seconds
sweepClosure = &tapLeaf.TapElementsLeaf
break
}
}
@@ -732,3 +822,289 @@ func getRedeemBranches(
return redeemBranches, nil
}
func computeVtxoTaprootScript(
userPubKey *secp256k1.PublicKey,
aspPublicKey *secp256k1.PublicKey,
exitDelay uint,
) (*secp256k1.PublicKey, *taproot.TapscriptElementsProof, error) {
redeemClosure := &tree.CSVSigClosure{
Pubkey: userPubKey,
Seconds: exitDelay,
}
forfeitClosure := &tree.ForfeitClosure{
Pubkey: userPubKey,
AspPubkey: aspPublicKey,
}
redeemLeaf, err := redeemClosure.Leaf()
if err != nil {
return nil, nil, err
}
forfeitLeaf, err := forfeitClosure.Leaf()
if err != nil {
return nil, nil, err
}
vtxoTaprootTree := taproot.AssembleTaprootScriptTree(*redeemLeaf, *forfeitLeaf)
root := vtxoTaprootTree.RootNode.TapHash()
unspendableKey := tree.UnspendableKey()
vtxoTaprootKey := taproot.ComputeTaprootOutputKey(unspendableKey, root[:])
redeemLeafHash := redeemLeaf.TapHash()
proofIndex := vtxoTaprootTree.LeafProofIndex[redeemLeafHash]
proof := vtxoTaprootTree.LeafMerkleProofs[proofIndex]
return vtxoTaprootKey, &proof, nil
}
func addVtxoInput(
updater *psetv2.Updater,
inputArgs psetv2.InputArgs,
exitDelay uint,
tapLeafProof *taproot.TapscriptElementsProof,
) error {
sequence, err := common.BIP68EncodeAsNumber(exitDelay)
if err != nil {
return nil
}
nextInputIndex := len(updater.Pset.Inputs)
if err := updater.AddInputs([]psetv2.InputArgs{inputArgs}); err != nil {
return err
}
updater.Pset.Inputs[nextInputIndex].Sequence = sequence
return updater.AddInTapLeafScript(
nextInputIndex,
psetv2.NewTapLeafScript(
*tapLeafProof,
tree.UnspendableKey(),
),
)
}
func coinSelectOnchain(targetAmount uint64, exclude []utxo) (utxos []utxo, delayedUtxos []utxo, change uint64, err error) {
_, onchainAddr, err := getAddress()
if err != nil {
return nil, nil, 0, err
}
fromExplorer, err := getOnchainUtxos(onchainAddr)
if err != nil {
return nil, nil, 0, err
}
utxos = make([]utxo, 0)
selectedAmount := uint64(0)
for _, utxo := range fromExplorer {
if selectedAmount >= targetAmount {
break
}
for _, excluded := range exclude {
if utxo.Txid == excluded.Txid && utxo.Vout == excluded.Vout {
continue
}
}
utxos = append(utxos, utxo)
selectedAmount += utxo.Amount
}
if selectedAmount >= targetAmount {
return utxos, nil, selectedAmount - targetAmount, nil
}
userPubKey, err := getWalletPublicKey()
if err != nil {
return nil, nil, 0, err
}
aspPublicKey, err := getServiceProviderPublicKey()
if err != nil {
return nil, nil, 0, err
}
exitDelay, err := getExitDelay()
if err != nil {
return nil, nil, 0, err
}
vtxoTapKey, _, err := computeVtxoTaprootScript(userPubKey, aspPublicKey, uint(exitDelay))
if err != nil {
return nil, nil, 0, err
}
_, net := getNetwork()
pay, err := payment.FromTweakedKey(vtxoTapKey, net, nil)
if err != nil {
return nil, nil, 0, err
}
addr, err := pay.TaprootAddress()
if err != nil {
return nil, nil, 0, err
}
fromExplorer, err = getOnchainUtxos(addr)
if err != nil {
return nil, nil, 0, err
}
delayedUtxos = make([]utxo, 0)
for _, utxo := range fromExplorer {
if selectedAmount >= targetAmount {
break
}
availableAt := time.Unix(utxo.Status.Blocktime, 0).Add(time.Duration(exitDelay) * time.Second)
if availableAt.After(time.Now()) {
continue
}
for _, excluded := range exclude {
if utxo.Txid == excluded.Txid && utxo.Vout == excluded.Vout {
continue
}
}
delayedUtxos = append(delayedUtxos, utxo)
selectedAmount += utxo.Amount
}
if selectedAmount < targetAmount {
return nil, nil, 0, fmt.Errorf("insufficient balance: %d to cover %d", selectedAmount, targetAmount)
}
return utxos, delayedUtxos, selectedAmount - targetAmount, nil
}
func addInputs(
updater *psetv2.Updater,
selected []utxo, // the utxos to add owned by the P2WPKH script
delayedSelected []utxo, // the utxos to add owned by the VTXO script
net *network.Network,
) error {
_, onchainAddr, err := getAddress()
if err != nil {
return err
}
changeScript, err := address.ToOutputScript(onchainAddr)
if err != nil {
return err
}
for _, coin := range selected {
fmt.Println("adding input", coin.Txid, coin.Vout)
if err := updater.AddInputs([]psetv2.InputArgs{
{
Txid: coin.Txid,
TxIndex: coin.Vout,
},
}); err != nil {
return err
}
assetID, err := elementsutil.AssetHashToBytes(coin.Asset)
if err != nil {
return err
}
value, err := elementsutil.ValueToBytes(coin.Amount)
if err != nil {
return err
}
witnessUtxo := transaction.TxOutput{
Asset: assetID,
Value: value,
Script: changeScript,
Nonce: []byte{0x00},
}
if err := updater.AddInWitnessUtxo(len(updater.Pset.Inputs)-1, &witnessUtxo); err != nil {
return err
}
}
if len(delayedSelected) > 0 {
userPubKey, err := getWalletPublicKey()
if err != nil {
return err
}
aspPublicKey, err := getServiceProviderPublicKey()
if err != nil {
return err
}
exitDelay, err := getExitDelay()
if err != nil {
return err
}
vtxoTapKey, leafProof, err := computeVtxoTaprootScript(userPubKey, aspPublicKey, uint(exitDelay))
if err != nil {
return err
}
pay, err := payment.FromTweakedKey(vtxoTapKey, net, nil)
if err != nil {
return err
}
addr, err := pay.TaprootAddress()
if err != nil {
return err
}
script, err := address.ToOutputScript(addr)
if err != nil {
return err
}
for _, coin := range delayedSelected {
if err := addVtxoInput(
updater,
psetv2.InputArgs{
Txid: coin.Txid,
TxIndex: coin.Vout,
},
uint(exitDelay),
leafProof,
); err != nil {
return err
}
assetID, err := elementsutil.AssetHashToBytes(coin.Asset)
if err != nil {
return err
}
value, err := elementsutil.ValueToBytes(coin.Amount)
if err != nil {
return err
}
witnessUtxo := transaction.TxOutput{
Asset: assetID,
Value: value,
Script: script,
Nonce: []byte{0x00},
}
if err := updater.AddInWitnessUtxo(len(updater.Pset.Inputs)-1, &witnessUtxo); err != nil {
return err
}
}
}
return nil
}

View File

@@ -78,15 +78,17 @@ func connectToAsp(ctx *cli.Context, net, url string) error {
}
defer close()
resp, err := client.GetPubkey(ctx.Context, &arkv1.GetPubkeyRequest{})
resp, err := client.GetInfo(ctx.Context, &arkv1.GetInfoRequest{})
if err != nil {
return err
}
return setState(map[string]string{
"ark_url": url,
"network": net,
"ark_pubkey": resp.Pubkey,
return setState(map[string]interface{}{
"ark_url": url,
"network": net,
"ark_pubkey": resp.Pubkey,
"ark_lifetime": resp.Lifetime,
"exit_delay": resp.ExitDelay,
})
}
@@ -114,7 +116,7 @@ func initWallet(ctx *cli.Context, key, password string) error {
passwordHash := hashPassword([]byte(password))
state := map[string]string{
state := map[string]interface{}{
"encrypted_private_key": hex.EncodeToString(encryptedPrivateKey),
"password_hash": hex.EncodeToString(passwordHash),
"public_key": hex.EncodeToString(privateKey.PubKey().SerializeCompressed()),

View File

@@ -29,9 +29,10 @@ var (
network.Testnet.Name: "https://blockstream.info/liquidtestnet/api",
}
initialState = map[string]string{
initialState = map[string]interface{}{
"ark_url": "",
"ark_pubkey": "",
"ark_lifetime": 0,
"encrypted_private_key": "",
"password_hash": "",
"public_key": "",
@@ -109,7 +110,7 @@ func cleanAndExpandPath(path string) string {
return filepath.Clean(os.ExpandEnv(path))
}
func getState() (map[string]string, error) {
func getState() (map[string]interface{}, error) {
file, err := os.ReadFile(statePath)
if err != nil {
if !os.IsNotExist(err) {
@@ -121,7 +122,7 @@ func getState() (map[string]string, error) {
return initialState, nil
}
data := map[string]string{}
data := map[string]interface{}{}
if err := json.Unmarshal(file, &data); err != nil {
return nil, err
}
@@ -137,7 +138,7 @@ func setInitialState() error {
return os.WriteFile(statePath, jsonString, 0755)
}
func setState(data map[string]string) error {
func setState(data map[string]interface{}) error {
currentData, err := getState()
if err != nil {
return err
@@ -157,8 +158,8 @@ func setState(data map[string]string) error {
return nil
}
func merge(maps ...map[string]string) map[string]string {
merge := make(map[string]string, 0)
func merge(maps ...map[string]interface{}) map[string]interface{} {
merge := make(map[string]interface{}, 0)
for _, m := range maps {
for k, v := range m {
merge[k] = v

View File

@@ -15,15 +15,9 @@ func receiveAction(ctx *cli.Context) error {
if err != nil {
return err
}
state, err := getState()
if err != nil {
return err
}
relays := []string{state["ark_url"]}
return printJSON(map[string]interface{}{
"offchain_address": offchainAddr,
"onchain_address": onchainAddr,
"relays": relays,
})
}

View File

@@ -4,7 +4,6 @@ import (
"bufio"
"fmt"
"log"
"math"
"os"
"strings"
"time"
@@ -12,7 +11,6 @@ import (
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/urfave/cli/v2"
"github.com/vulpemventures/go-elements/address"
"github.com/vulpemventures/go-elements/psetv2"
)
var (
@@ -20,7 +18,7 @@ var (
Name: "address",
Usage: "main chain address receiving the redeeemed VTXO",
Value: "",
Required: true,
Required: false,
}
amountToRedeemFlag = cli.Uint64Flag{
@@ -50,20 +48,9 @@ func redeemAction(ctx *cli.Context) error {
amount := ctx.Uint64("amount")
force := ctx.Bool("force")
if len(addr) <= 0 {
if len(addr) <= 0 && !force {
return fmt.Errorf("missing address flag (--address)")
}
if _, err := address.ToOutputScript(addr); err != nil {
return fmt.Errorf("invalid onchain address")
}
net, err := address.NetworkForAddress(addr)
if err != nil {
return fmt.Errorf("invalid onchain address: unknown network")
}
_, liquidNet := getNetwork()
if net.Name != liquidNet.Name {
return fmt.Errorf("invalid onchain address: must be for %s network", liquidNet.Name)
}
if !force && amount <= 0 {
return fmt.Errorf("missing amount flag (--amount)")
@@ -74,13 +61,26 @@ func redeemAction(ctx *cli.Context) error {
fmt.Printf("WARNING: unilateral exit (--force) ignores --amount flag, it will redeem all your VTXOs\n")
}
return unilateralRedeem(ctx, addr)
return unilateralRedeem(ctx)
}
return collaborativeRedeem(ctx, addr, amount)
}
func collaborativeRedeem(ctx *cli.Context, addr string, amount uint64) error {
if _, err := address.ToOutputScript(addr); err != nil {
return fmt.Errorf("invalid onchain address")
}
net, err := address.NetworkForAddress(addr)
if err != nil {
return fmt.Errorf("invalid onchain address: unknown network")
}
_, liquidNet := getNetwork()
if net.Name != liquidNet.Name {
return fmt.Errorf("invalid onchain address: must be for %s network", liquidNet.Name)
}
if isConf, _ := address.IsConfidential(addr); isConf {
info, _ := address.FromConfidential(addr)
addr = info.Address
@@ -173,12 +173,7 @@ func collaborativeRedeem(ctx *cli.Context, addr string, amount uint64) error {
return nil
}
func unilateralRedeem(ctx *cli.Context, addr string) error {
onchainScript, err := address.ToOutputScript(addr)
if err != nil {
return err
}
func unilateralRedeem(ctx *cli.Context) error {
client, close, err := getClientFromState(ctx)
if err != nil {
return err
@@ -202,20 +197,11 @@ func unilateralRedeem(ctx *cli.Context, addr string) error {
totalVtxosAmount += vtxo.amount
}
ok := askForConfirmation(fmt.Sprintf("redeem %d sats to %s ?", totalVtxosAmount, addr))
ok := askForConfirmation(fmt.Sprintf("redeem %d sats ?", totalVtxosAmount))
if !ok {
return fmt.Errorf("aborting unilateral exit")
}
finalPset, err := psetv2.New(nil, nil, nil)
if err != nil {
return err
}
updater, err := psetv2.NewUpdater(finalPset)
if err != nil {
return err
}
// transactionsMap avoid duplicates
transactionsMap := make(map[string]struct{}, 0)
transactions := make([]string, 0)
@@ -226,10 +212,6 @@ func unilateralRedeem(ctx *cli.Context, addr string) error {
}
for _, branch := range redeemBranches {
if err := branch.AddVtxoInput(updater); err != nil {
return err
}
branchTxs, err := branch.RedeemPath()
if err != nil {
return err
@@ -243,48 +225,6 @@ func unilateralRedeem(ctx *cli.Context, addr string) error {
}
}
_, net := getNetwork()
outputs := []psetv2.OutputArgs{
{
Asset: net.AssetID,
Amount: totalVtxosAmount,
Script: onchainScript,
},
}
if err := updater.AddOutputs(outputs); err != nil {
return err
}
utx, err := updater.Pset.UnsignedTx()
if err != nil {
return err
}
vBytes := utx.VirtualSize()
feeAmount := uint64(math.Ceil(float64(vBytes) * 0.25))
if totalVtxosAmount-feeAmount <= 0 {
return fmt.Errorf("not enough VTXOs to pay the fees (%d sats), aborting unilateral exit", feeAmount)
}
updater.Pset.Outputs[0].Value = totalVtxosAmount - feeAmount
if err := updater.AddOutputs([]psetv2.OutputArgs{
{
Asset: net.AssetID,
Amount: feeAmount,
},
}); err != nil {
return err
}
prvKey, err := privateKeyFromPassword()
if err != nil {
return err
}
for i, txHex := range transactions {
for {
txid, err := explorer.Broadcast(txHex)
@@ -303,43 +243,6 @@ func unilateralRedeem(ctx *cli.Context, addr string) error {
}
}
if err := signPset(finalPset, explorer, prvKey); err != nil {
return err
}
for i, input := range finalPset.Inputs {
if len(input.TapScriptSig) > 0 || len(input.PartialSigs) > 0 {
if err := psetv2.Finalize(finalPset, i); err != nil {
return err
}
}
}
signedTx, err := psetv2.Extract(finalPset)
if err != nil {
return err
}
hex, err := signedTx.ToHex()
if err != nil {
return err
}
for {
id, err := explorer.Broadcast(hex)
if err != nil {
if strings.Contains(strings.ToLower(err.Error()), "bad-txns-inputs-missingorspent") {
time.Sleep(1 * time.Second)
continue
}
return err
}
if id != "" {
fmt.Printf("(final) redeem tx %s\n", id)
break
}
}
return nil
}

View File

@@ -4,10 +4,13 @@ import (
"bytes"
"encoding/json"
"fmt"
"math"
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/ark-network/ark/common"
"github.com/urfave/cli/v2"
"github.com/vulpemventures/go-elements/address"
"github.com/vulpemventures/go-elements/psetv2"
)
type receiver struct {
@@ -15,6 +18,11 @@ type receiver struct {
Amount uint64 `json:"amount"`
}
func (r *receiver) IsOnchain() bool {
_, err := address.ToOutputScript(r.To)
return err == nil
}
var (
receiversFlag = cli.StringFlag{
Name: "receivers",
@@ -22,7 +30,7 @@ var (
}
toFlag = cli.StringFlag{
Name: "to",
Usage: "ark address of the recipient",
Usage: "address of the recipient",
}
amountFlag = cli.Uint64Flag{
Name: "amount",
@@ -63,6 +71,33 @@ func sendAction(ctx *cli.Context) error {
return fmt.Errorf("no receivers specified")
}
onchainReceivers := make([]receiver, 0)
offchainReceivers := make([]receiver, 0)
for _, receiver := range receiversJSON {
if receiver.IsOnchain() {
onchainReceivers = append(onchainReceivers, receiver)
} else {
offchainReceivers = append(offchainReceivers, receiver)
}
}
if len(onchainReceivers) > 0 {
if err := sendOnchain(ctx, onchainReceivers); err != nil {
return err
}
}
if len(offchainReceivers) > 0 {
if err := sendOffchain(ctx, offchainReceivers); err != nil {
return err
}
}
return nil
}
func sendOffchain(ctx *cli.Context, receivers []receiver) error {
offchainAddr, _, err := getAddress()
if err != nil {
return err
@@ -76,7 +111,7 @@ func sendAction(ctx *cli.Context) error {
receiversOutput := make([]*arkv1.Output, 0)
sumOfReceivers := uint64(0)
for _, receiver := range receiversJSON {
for _, receiver := range receivers {
_, _, aspKey, err := common.DecodeAddress(receiver.To)
if err != nil {
return fmt.Errorf("invalid receiver address: %s", err)
@@ -163,11 +198,169 @@ func sendAction(ctx *cli.Context) error {
return err
}
if err := printJSON(map[string]interface{}{
return printJSON(map[string]interface{}{
"pool_txid": poolTxID,
})
}
func sendOnchain(ctx *cli.Context, receivers []receiver) error {
pset, err := psetv2.New(nil, nil, nil)
if err != nil {
return err
}
updater, err := psetv2.NewUpdater(pset)
if err != nil {
return err
}
_, net := getNetwork()
targetAmount := uint64(0)
for _, receiver := range receivers {
targetAmount += receiver.Amount
if receiver.Amount < DUST {
return fmt.Errorf("invalid amount (%d), must be greater than dust %d", receiver.Amount, DUST)
}
script, err := address.ToOutputScript(receiver.To)
if err != nil {
return err
}
if err := updater.AddOutputs([]psetv2.OutputArgs{
{
Asset: net.AssetID,
Amount: receiver.Amount,
Script: script,
},
}); err != nil {
return err
}
}
selected, delayedSelected, change, err := coinSelectOnchain(targetAmount, nil)
if err != nil {
return err
}
if err := addInputs(updater, selected, delayedSelected, net); err != nil {
return err
}
if change > 0 {
_, changeAddr, err := getAddress()
if err != nil {
return err
}
changeScript, err := address.ToOutputScript(changeAddr)
if err != nil {
return err
}
if err := updater.AddOutputs([]psetv2.OutputArgs{
{
Asset: net.AssetID,
Amount: change,
Script: changeScript,
},
}); err != nil {
return err
}
}
utx, err := updater.Pset.UnsignedTx()
if err != nil {
return err
}
vBytes := utx.VirtualSize()
feeAmount := uint64(math.Ceil(float64(vBytes) * 0.5))
if change > feeAmount {
updater.Pset.Outputs[len(updater.Pset.Outputs)-1].Value = change - feeAmount
} else if change == feeAmount {
updater.Pset.Outputs = updater.Pset.Outputs[:len(updater.Pset.Outputs)-1]
} else { // change < feeAmount
if change > 0 {
updater.Pset.Outputs = updater.Pset.Outputs[:len(updater.Pset.Outputs)-1]
}
// reselect the difference
selected, delayedSelected, newChange, err := coinSelectOnchain(
feeAmount-change,
append(selected, delayedSelected...),
)
if err != nil {
return err
}
if err := addInputs(updater, selected, delayedSelected, net); err != nil {
return err
}
if newChange > 0 {
_, changeAddr, err := getAddress()
if err != nil {
return err
}
changeScript, err := address.ToOutputScript(changeAddr)
if err != nil {
return err
}
if err := updater.AddOutputs([]psetv2.OutputArgs{
{
Asset: net.AssetID,
Amount: newChange,
Script: changeScript,
},
}); err != nil {
return err
}
}
}
if err := updater.AddOutputs([]psetv2.OutputArgs{
{
Asset: net.AssetID,
Amount: feeAmount,
},
}); err != nil {
return err
}
return nil
prvKey, err := privateKeyFromPassword()
if err != nil {
return err
}
explorer := NewExplorer()
if err := signPset(updater.Pset, explorer, prvKey); err != nil {
return err
}
if err := psetv2.FinalizeAll(updater.Pset); err != nil {
return err
}
extracted, err := psetv2.Extract(pset)
if err != nil {
return err
}
hex, err := extracted.ToHex()
if err != nil {
return err
}
txid, err := explorer.Broadcast(hex)
if err != nil {
return err
}
return printJSON(map[string]interface{}{
"txid": txid,
})
}

View File

@@ -122,20 +122,29 @@ func signPset(
continue
}
pubkey := prvKey.PubKey()
vtxoLeaf, err := tree.VtxoScript(pubkey)
if err != nil {
return err
}
if len(input.TapLeafScript) > 0 {
genesis, err := chainhash.NewHashFromStr(liquidNet.GenesisBlockHash)
if err != nil {
return err
}
pubkey := prvKey.PubKey()
for _, leaf := range input.TapLeafScript {
if bytes.Equal(leaf.Script, vtxoLeaf.Script) {
closure, err := tree.DecodeClosure(leaf.Script)
if err != nil {
return err
}
sign := false
switch c := closure.(type) {
case *tree.CSVSigClosure:
sign = bytes.Equal(c.Pubkey.SerializeCompressed()[1:], pubkey.SerializeCompressed()[1:])
case *tree.ForfeitClosure:
sign = bytes.Equal(c.Pubkey.SerializeCompressed()[1:], pubkey.SerializeCompressed()[1:])
}
if sign {
hash := leaf.TapHash()
preimage := utx.HashForWitnessV1(

View File

@@ -15,8 +15,6 @@ import (
type RedeemBranch interface {
// RedeemPath returns the list of transactions to broadcast in order to access the vtxo output
RedeemPath() ([]string, error)
// AddInput adds the vtxo input created by the branch
AddVtxoInput(updater *psetv2.Updater) error
// ExpireAt returns the expiration time of the branch
ExpireAt() (*time.Time, error)
}
@@ -92,89 +90,41 @@ func (r *redeemBranch) RedeemPath() ([]string, error) {
}
for _, leaf := range input.TapLeafScript {
isSweep, _, _, err := tree.DecodeSweepScript(leaf.Script)
closure, err := tree.DecodeClosure(leaf.Script)
if err != nil {
return nil, err
}
if isSweep {
continue
}
switch closure.(type) {
case *tree.UnrollClosure:
controlBlock, err := leaf.ControlBlock.ToBytes()
if err != nil {
return nil, err
}
controlBlock, err := leaf.ControlBlock.ToBytes()
if err != nil {
return nil, err
}
unsignedTx, err := pset.UnsignedTx()
if err != nil {
return nil, err
}
unsignedTx, err := pset.UnsignedTx()
if err != nil {
return nil, err
}
unsignedTx.Inputs[i].Witness = [][]byte{
leaf.Script,
controlBlock[:],
}
unsignedTx.Inputs[i].Witness = [][]byte{
leaf.Script,
controlBlock[:],
hex, err := unsignedTx.ToHex()
if err != nil {
return nil, err
}
transactions = append(transactions, hex)
}
hex, err := unsignedTx.ToHex()
if err != nil {
return nil, err
}
transactions = append(transactions, hex)
break
}
}
}
return transactions, nil
}
// AddVtxoInput is a wrapper around psetv2.Updater adding a taproot input letting to spend the vtxo output
func (r *redeemBranch) AddVtxoInput(updater *psetv2.Updater) error {
walletPubkey, err := getWalletPublicKey()
if err != nil {
return err
}
nextInputIndex := len(updater.Pset.Inputs)
if err := updater.AddInputs([]psetv2.InputArgs{
{
Txid: r.vtxo.txid,
TxIndex: r.vtxo.vout,
},
}); err != nil {
return err
}
// add taproot tree letting to spend the vtxo
checksigLeaf, err := tree.VtxoScript(walletPubkey)
if err != nil {
return nil
}
vtxoTaprootTree := taproot.AssembleTaprootScriptTree(
*checksigLeaf,
*r.sweepClosure,
)
proofIndex := vtxoTaprootTree.LeafProofIndex[checksigLeaf.TapHash()]
if err := updater.AddInTapLeafScript(
nextInputIndex,
psetv2.NewTapLeafScript(
vtxoTaprootTree.LeafMerkleProofs[proofIndex],
r.internalKey,
),
); err != nil {
return err
}
return nil
}
func (r *redeemBranch) ExpireAt() (*time.Time, error) {
lastKnownBlocktime := int64(0)

View File

@@ -3,6 +3,7 @@ package tree
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/ark-network/ark/common"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
@@ -17,9 +18,53 @@ const (
OP_PUSHCURRENTINPUTINDEX = 0xcd
)
// VtxoScript returns a simple checksig script for a given pubkey
func VtxoScript(pubkey *secp256k1.PublicKey) (*taproot.TapElementsLeaf, error) {
script, err := checksigScript(pubkey)
type Closure interface {
Leaf() (*taproot.TapElementsLeaf, error)
Decode(script []byte) (bool, error)
}
type UnrollClosure struct {
LeftKey, RightKey *secp256k1.PublicKey
LeftAmount, RightAmount uint64
}
type CSVSigClosure struct {
Pubkey *secp256k1.PublicKey
Seconds uint
}
type ForfeitClosure struct {
Pubkey *secp256k1.PublicKey
AspPubkey *secp256k1.PublicKey
}
func DecodeClosure(script []byte) (Closure, error) {
var closure Closure
closure = &UnrollClosure{}
if valid, err := closure.Decode(script); err == nil && valid {
return closure, nil
}
closure = &CSVSigClosure{}
if valid, err := closure.Decode(script); err == nil && valid {
return closure, nil
}
closure = &ForfeitClosure{}
if valid, err := closure.Decode(script); err == nil && valid {
return closure, nil
}
return nil, fmt.Errorf("invalid closure script")
}
func (f *ForfeitClosure) Leaf() (*taproot.TapElementsLeaf, error) {
aspKeyBytes := schnorr.SerializePubKey(f.AspPubkey)
userKeyBytes := schnorr.SerializePubKey(f.Pubkey)
script, err := txscript.NewScriptBuilder().AddData(aspKeyBytes).AddOp(txscript.OP_CHECKSIGVERIFY).AddData(userKeyBytes).AddOp(txscript.OP_CHECKSIG).Script()
if err != nil {
return nil, err
}
@@ -28,67 +73,152 @@ func VtxoScript(pubkey *secp256k1.PublicKey) (*taproot.TapElementsLeaf, error) {
return &tapLeaf, nil
}
// SweepScript returns a taproot leaf letting the owner of the key to spend the output after a given timeDelta
func SweepScript(sweepKey *secp256k1.PublicKey, seconds uint) (*taproot.TapElementsLeaf, error) {
sweepScript, err := csvChecksigScript(sweepKey, seconds)
func (f *ForfeitClosure) Decode(script []byte) (bool, error) {
valid, aspPubKey, err := decodeChecksigScript(script)
if err != nil {
return false, err
}
if !valid {
return false, nil
}
valid, pubkey, err := decodeChecksigScript(script[33:])
if err != nil {
return false, err
}
if !valid {
return false, nil
}
f.Pubkey = pubkey
f.AspPubkey = aspPubKey
rebuilt, err := f.Leaf()
if err != nil {
return false, err
}
if !bytes.Equal(rebuilt.Script, script) {
return false, nil
}
return true, nil
}
func (d *CSVSigClosure) Leaf() (*taproot.TapElementsLeaf, error) {
script, err := csvChecksigScript(d.Pubkey, d.Seconds)
if err != nil {
return nil, err
}
tapLeaf := taproot.NewBaseTapElementsLeaf(sweepScript)
tapLeaf := taproot.NewBaseTapElementsLeaf(script)
return &tapLeaf, nil
}
// BranchScript returns a taproot leaf that will split the coin in two outputs
// each output (left and right) will have the given amount and the given taproot key as witness program
func BranchScript(
leftKey, rightKey *secp256k1.PublicKey, leftAmount, rightAmount uint64,
) taproot.TapElementsLeaf {
nextScriptLeft := withOutput(txscript.OP_0, schnorr.SerializePubKey(leftKey), leftAmount, rightKey != nil)
branchScript := append([]byte{}, nextScriptLeft...)
if rightKey != nil {
nextScriptRight := withOutput(txscript.OP_1, schnorr.SerializePubKey(rightKey), rightAmount, false)
branchScript = append(branchScript, nextScriptRight...)
func (d *CSVSigClosure) Decode(script []byte) (bool, error) {
csvIndex := bytes.Index(script, []byte{txscript.OP_CHECKSEQUENCEVERIFY, txscript.OP_DROP})
if csvIndex == -1 || csvIndex == 0 {
return false, nil
}
return taproot.NewBaseTapElementsLeaf(branchScript)
sequence := script[1:csvIndex]
seconds, err := common.BIP68Decode(sequence)
if err != nil {
return false, err
}
checksigScript := script[csvIndex+2:]
valid, pubkey, err := decodeChecksigScript(checksigScript)
if err != nil {
return false, err
}
if !valid {
return false, nil
}
rebuilt, err := csvChecksigScript(pubkey, seconds)
if err != nil {
return false, err
}
if !bytes.Equal(rebuilt, script) {
return false, nil
}
d.Pubkey = pubkey
d.Seconds = seconds
return valid, nil
}
func decodeBranchScript(script []byte) (valid bool, leftKey, rightKey *secp256k1.PublicKey, leftAmount, rightAmount uint64, err error) {
func (c *UnrollClosure) Leaf() (*taproot.TapElementsLeaf, error) {
if c.LeftKey == nil || c.LeftAmount == 0 {
return nil, fmt.Errorf("left key and amount are required")
}
nextScriptLeft := withOutput(txscript.OP_0, schnorr.SerializePubKey(c.LeftKey), c.LeftAmount, c.RightKey != nil)
branchScript := append([]byte{}, nextScriptLeft...)
if c.RightKey != nil {
if c.RightAmount == 0 {
return nil, fmt.Errorf("right amount is required")
}
nextScriptRight := withOutput(txscript.OP_1, schnorr.SerializePubKey(c.RightKey), c.RightAmount, false)
branchScript = append(branchScript, nextScriptRight...)
}
leaf := taproot.NewBaseTapElementsLeaf(branchScript)
return &leaf, nil
}
func (c *UnrollClosure) Decode(script []byte) (valid bool, err error) {
if len(script) != 52 && len(script) != 104 {
return false, nil, nil, 0, 0, nil
return false, nil
}
isLeftOnly := len(script) == 52
validLeft, leftKey, leftAmount, err := decodeWithOutputScript(script[:52], txscript.OP_0, !isLeftOnly)
if err != nil {
return false, nil, nil, 0, 0, err
return false, err
}
if !validLeft {
return false, nil, nil, 0, 0, nil
return false, nil
}
c.LeftAmount = leftAmount
c.LeftKey = leftKey
if isLeftOnly {
return true, leftKey, nil, leftAmount, 0, nil
return true, nil
}
validRight, rightKey, rightAmount, err := decodeWithOutputScript(script[52:], txscript.OP_1, false)
if err != nil {
return false, nil, nil, 0, 0, err
return false, err
}
if !validRight {
return false, nil, nil, 0, 0, nil
return false, nil
}
rebuilt := BranchScript(leftKey, rightKey, leftAmount, rightAmount)
c.RightAmount = rightAmount
c.RightKey = rightKey
rebuilt, err := c.Leaf()
if err != nil {
return false, err
}
if !bytes.Equal(rebuilt.Script, script) {
return false, nil, nil, 0, 0, nil
return false, nil
}
return true, leftKey, rightKey, leftAmount, rightAmount, nil
return true, nil
}
func decodeWithOutputScript(script []byte, expectedIndex byte, isVerify bool) (valid bool, pubkey *secp256k1.PublicKey, amount uint64, err error) {
@@ -139,53 +269,9 @@ func decodeChecksigScript(script []byte) (valid bool, pubkey *secp256k1.PublicKe
return false, nil, err
}
rebuilt, err := checksigScript(pubkey)
if err != nil {
return false, nil, err
}
if !bytes.Equal(rebuilt, script) {
return false, nil, nil
}
return true, pubkey, nil
}
func DecodeSweepScript(script []byte) (valid bool, aspPubKey *secp256k1.PublicKey, seconds uint, err error) {
csvIndex := bytes.Index(script, []byte{txscript.OP_CHECKSEQUENCEVERIFY, txscript.OP_DROP})
if csvIndex == -1 || csvIndex == 0 {
return false, nil, 0, nil
}
sequence := script[1:csvIndex]
seconds, err = common.BIP68Decode(sequence)
if err != nil {
return false, nil, 0, err
}
checksigScript := script[csvIndex+2:]
valid, aspPubKey, err = decodeChecksigScript(checksigScript)
if err != nil {
return false, nil, 0, err
}
if !valid {
return false, nil, 0, nil
}
rebuilt, err := csvChecksigScript(aspPubKey, seconds)
if err != nil {
return false, nil, 0, err
}
if !bytes.Equal(rebuilt, script) {
return false, nil, 0, nil
}
return valid, aspPubKey, seconds, nil
}
// checkSequenceVerifyScript without checksig
func checkSequenceVerifyScript(seconds uint) ([]byte, error) {
sequence, err := common.BIP68Encode(seconds)

View File

@@ -229,35 +229,33 @@ func validateNodeTransaction(
return ErrInvalidTaprootScript
}
isSweepLeaf, aspKey, seconds, err := DecodeSweepScript(tapLeaf.Script)
close, err := DecodeClosure(tapLeaf.Script)
if err != nil {
return fmt.Errorf("invalid sweep script: %w", err)
}
if isSweepLeaf {
if !aspKey.IsEqual(aspKey) {
return ErrInvalidASP
}
if int64(seconds) != expectedSequenceSeconds {
return ErrInvalidSweepSequence
}
sweepLeafFound = true
continue
}
isBranchLeaf, leftKey, rightKey, leftAmount, rightAmount, err := decodeBranchScript(tapLeaf.Script)
if err != nil {
return fmt.Errorf("invalid branch script: %w", err)
}
switch c := close.(type) {
case *CSVSigClosure:
isASP := c.Pubkey.IsEqual(expectedPublicKeyASP)
isSweepDelay := int64(c.Seconds) == expectedSequenceSeconds
if isBranchLeaf {
if isASP && !isSweepDelay {
return ErrInvalidSweepSequence
}
if isSweepDelay && !isASP {
return ErrInvalidASP
}
if isASP && isSweepDelay {
sweepLeafFound = true
}
case *UnrollClosure:
branchLeafFound = true
// check outputs
nbOuts := len(childTx.Outputs)
if leftKey != nil && rightKey != nil {
if c.LeftKey != nil && c.RightKey != nil {
if nbOuts != 3 {
return ErrNumberOfOutputs
}
@@ -270,26 +268,29 @@ func validateNodeTransaction(
leftWitnessProgram := childTx.Outputs[0].Script[2:]
leftOutputAmount := childTx.Outputs[0].Value
if !bytes.Equal(leftWitnessProgram, schnorr.SerializePubKey(leftKey)) {
if !bytes.Equal(leftWitnessProgram, schnorr.SerializePubKey(c.LeftKey)) {
return ErrInvalidLeftOutput
}
if leftAmount != leftOutputAmount {
if c.LeftAmount != leftOutputAmount {
return ErrInvalidLeftOutput
}
if rightKey != nil {
if c.RightKey != nil {
rightWitnessProgram := childTx.Outputs[1].Script[2:]
rightOutputAmount := childTx.Outputs[1].Value
if !bytes.Equal(rightWitnessProgram, schnorr.SerializePubKey(rightKey)) {
if !bytes.Equal(rightWitnessProgram, schnorr.SerializePubKey(c.RightKey)) {
return ErrInvalidRightOutput
}
if rightAmount != rightOutputAmount {
if c.RightAmount != rightOutputAmount {
return ErrInvalidRightOutput
}
}
default:
continue
}
}

View File

@@ -77,6 +77,28 @@
]
}
},
"/v1/info": {
"get": {
"operationId": "ArkService_GetInfo",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1GetInfoResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"tags": [
"ArkService"
]
}
},
"/v1/payment/claim": {
"post": {
"operationId": "ArkService_ClaimPayment",
@@ -203,28 +225,6 @@
]
}
},
"/v1/pubkey": {
"get": {
"operationId": "ArkService_GetPubkey",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1GetPubkeyResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"tags": [
"ArkService"
]
}
},
"/v1/round/{txid}": {
"get": {
"operationId": "ArkService_GetRound",
@@ -367,11 +367,19 @@
}
}
},
"v1GetPubkeyResponse": {
"v1GetInfoResponse": {
"type": "object",
"properties": {
"pubkey": {
"type": "string"
},
"lifetime": {
"type": "string",
"format": "int64"
},
"exitDelay": {
"type": "string",
"format": "int64"
}
}
},

View File

@@ -48,9 +48,9 @@ service ArkService {
get: "/v1/vtxos/{address}"
};
}
rpc GetPubkey(GetPubkeyRequest) returns (GetPubkeyResponse) {
rpc GetInfo(GetInfoRequest) returns (GetInfoResponse) {
option (google.api.http) = {
get: "/v1/pubkey"
get: "/v1/info"
};
}
}
@@ -172,8 +172,10 @@ message Vtxo {
string pool_txid = 4;
}
message GetPubkeyRequest {}
message GetInfoRequest {}
message GetPubkeyResponse {
message GetInfoResponse {
string pubkey = 1;
int64 lifetime = 2;
int64 exit_delay = 3;
}

View File

@@ -1388,14 +1388,14 @@ func (x *Vtxo) GetPoolTxid() string {
return ""
}
type GetPubkeyRequest struct {
type GetInfoRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *GetPubkeyRequest) Reset() {
*x = GetPubkeyRequest{}
func (x *GetInfoRequest) Reset() {
*x = GetInfoRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_ark_v1_service_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -1403,13 +1403,13 @@ func (x *GetPubkeyRequest) Reset() {
}
}
func (x *GetPubkeyRequest) String() string {
func (x *GetInfoRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPubkeyRequest) ProtoMessage() {}
func (*GetInfoRequest) ProtoMessage() {}
func (x *GetPubkeyRequest) ProtoReflect() protoreflect.Message {
func (x *GetInfoRequest) ProtoReflect() protoreflect.Message {
mi := &file_ark_v1_service_proto_msgTypes[26]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -1421,21 +1421,23 @@ func (x *GetPubkeyRequest) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
// Deprecated: Use GetPubkeyRequest.ProtoReflect.Descriptor instead.
func (*GetPubkeyRequest) Descriptor() ([]byte, []int) {
// Deprecated: Use GetInfoRequest.ProtoReflect.Descriptor instead.
func (*GetInfoRequest) Descriptor() ([]byte, []int) {
return file_ark_v1_service_proto_rawDescGZIP(), []int{26}
}
type GetPubkeyResponse struct {
type GetInfoResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Pubkey string `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"`
Pubkey string `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"`
Lifetime int64 `protobuf:"varint,2,opt,name=lifetime,proto3" json:"lifetime,omitempty"`
ExitDelay int64 `protobuf:"varint,3,opt,name=exit_delay,json=exitDelay,proto3" json:"exit_delay,omitempty"`
}
func (x *GetPubkeyResponse) Reset() {
*x = GetPubkeyResponse{}
func (x *GetInfoResponse) Reset() {
*x = GetInfoResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_ark_v1_service_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -1443,13 +1445,13 @@ func (x *GetPubkeyResponse) Reset() {
}
}
func (x *GetPubkeyResponse) String() string {
func (x *GetInfoResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPubkeyResponse) ProtoMessage() {}
func (*GetInfoResponse) ProtoMessage() {}
func (x *GetPubkeyResponse) ProtoReflect() protoreflect.Message {
func (x *GetInfoResponse) ProtoReflect() protoreflect.Message {
mi := &file_ark_v1_service_proto_msgTypes[27]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -1461,18 +1463,32 @@ func (x *GetPubkeyResponse) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
// Deprecated: Use GetPubkeyResponse.ProtoReflect.Descriptor instead.
func (*GetPubkeyResponse) Descriptor() ([]byte, []int) {
// Deprecated: Use GetInfoResponse.ProtoReflect.Descriptor instead.
func (*GetInfoResponse) Descriptor() ([]byte, []int) {
return file_ark_v1_service_proto_rawDescGZIP(), []int{27}
}
func (x *GetPubkeyResponse) GetPubkey() string {
func (x *GetInfoResponse) GetPubkey() string {
if x != nil {
return x.Pubkey
}
return ""
}
func (x *GetInfoResponse) GetLifetime() int64 {
if x != nil {
return x.Lifetime
}
return 0
}
func (x *GetInfoResponse) GetExitDelay() int64 {
if x != nil {
return x.ExitDelay
}
return 0
}
var File_ark_v1_service_proto protoreflect.FileDescriptor
var file_ark_v1_service_proto_rawDesc = []byte{
@@ -1590,77 +1606,80 @@ var file_ark_v1_service_proto_rawDesc = []byte{
0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74,
0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a,
0x09, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x69, 0x64, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65,
0x74, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2b,
0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x32, 0xfd, 0x06, 0x0a, 0x0a,
0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x73, 0x0a, 0x0f, 0x52, 0x65,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e,
0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e,
0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12,
0x67, 0x0a, 0x0c, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12,
0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61,
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61,
0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x73, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x61,
0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72,
0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79,
0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72,
0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79,
0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79,
0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x57, 0x0a,
0x08, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52,
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f,
0x7b, 0x74, 0x78, 0x69, 0x64, 0x7d, 0x12, 0x65, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65,
0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76,
0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12,
0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x50, 0x0a,
0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x13, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50,
0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, 0x6b,
0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x69,
0x6e, 0x67, 0x2f, 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12,
0x55, 0x0a, 0x06, 0x46, 0x61, 0x75, 0x63, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x61, 0x72, 0x6b, 0x2e,
0x76, 0x31, 0x2e, 0x46, 0x61, 0x75, 0x63, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x61, 0x75, 0x63, 0x65, 0x74,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16,
0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x61, 0x75, 0x63, 0x65, 0x74, 0x2f, 0x7b, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x5d, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74,
0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e,
0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15,
0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78, 0x6f, 0x73, 0x2f, 0x7b, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x54, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6b,
0x65, 0x79, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50,
0x75, 0x62, 0x6b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61,
0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12,
0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x42, 0x92, 0x01, 0x0a, 0x0a,
0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f,
0x72, 0x6b, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, 0x6b,
0x2f, 0x76, 0x31, 0x3b, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa,
0x02, 0x06, 0x41, 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, 0x56,
0x31, 0xe2, 0x02, 0x12, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, 0x31,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x52, 0x08, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x47, 0x65,
0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x64, 0x0a, 0x0f,
0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x69, 0x66, 0x65, 0x74,
0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6c, 0x69, 0x66, 0x65, 0x74,
0x69, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x61,
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65, 0x78, 0x69, 0x74, 0x44, 0x65, 0x6c,
0x61, 0x79, 0x32, 0xf5, 0x06, 0x0a, 0x0a, 0x41, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x12, 0x73, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79,
0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a,
0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x72, 0x65,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x67, 0x0a, 0x0c, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61,
0x69, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x76,
0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x12,
0x73, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61,
0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61,
0x6c, 0x69, 0x7a, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x01, 0x2a, 0x22, 0x14,
0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x66, 0x69, 0x6e, 0x61,
0x6c, 0x69, 0x7a, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64,
0x12, 0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75,
0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x72, 0x6b, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31,
0x2f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x7b, 0x74, 0x78, 0x69, 0x64, 0x7d, 0x12, 0x65, 0x0a,
0x0e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12,
0x1d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e,
0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e,
0x74, 0x73, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x13, 0x2e, 0x61,
0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x14, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12,
0x15, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x2f, 0x7b, 0x70, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x55, 0x0a, 0x06, 0x46, 0x61, 0x75, 0x63, 0x65, 0x74,
0x12, 0x15, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x61, 0x75, 0x63, 0x65, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
0x2e, 0x46, 0x61, 0x75, 0x63, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x61, 0x75,
0x63, 0x65, 0x74, 0x2f, 0x7b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x5d, 0x0a,
0x09, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x72, 0x6b,
0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x56, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x74, 0x78,
0x6f, 0x73, 0x2f, 0x7b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0x4c, 0x0a, 0x07,
0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x17, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a,
0x12, 0x08, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x92, 0x01, 0x0a, 0x0a, 0x63,
0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6b, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x2f, 0x61, 0x72, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x73, 0x70, 0x65, 0x63, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, 0x6b, 0x2f,
0x76, 0x31, 0x3b, 0x61, 0x72, 0x6b, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, 0x02,
0x06, 0x41, 0x72, 0x6b, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31,
0xe2, 0x02, 0x12, 0x41, 0x72, 0x6b, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x72, 0x6b, 0x3a, 0x3a, 0x56, 0x31, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1703,8 +1722,8 @@ var file_ark_v1_service_proto_goTypes = []interface{}{
(*ListVtxosRequest)(nil), // 23: ark.v1.ListVtxosRequest
(*ListVtxosResponse)(nil), // 24: ark.v1.ListVtxosResponse
(*Vtxo)(nil), // 25: ark.v1.Vtxo
(*GetPubkeyRequest)(nil), // 26: ark.v1.GetPubkeyRequest
(*GetPubkeyResponse)(nil), // 27: ark.v1.GetPubkeyResponse
(*GetInfoRequest)(nil), // 26: ark.v1.GetInfoRequest
(*GetInfoResponse)(nil), // 27: ark.v1.GetInfoResponse
}
var file_ark_v1_service_proto_depIdxs = []int32{
9, // 0: ark.v1.RegisterPaymentRequest.inputs:type_name -> ark.v1.Input
@@ -1728,7 +1747,7 @@ var file_ark_v1_service_proto_depIdxs = []int32{
19, // 18: ark.v1.ArkService.Ping:input_type -> ark.v1.PingRequest
21, // 19: ark.v1.ArkService.Faucet:input_type -> ark.v1.FaucetRequest
23, // 20: ark.v1.ArkService.ListVtxos:input_type -> ark.v1.ListVtxosRequest
26, // 21: ark.v1.ArkService.GetPubkey:input_type -> ark.v1.GetPubkeyRequest
26, // 21: ark.v1.ArkService.GetInfo:input_type -> ark.v1.GetInfoRequest
1, // 22: ark.v1.ArkService.RegisterPayment:output_type -> ark.v1.RegisterPaymentResponse
3, // 23: ark.v1.ArkService.ClaimPayment:output_type -> ark.v1.ClaimPaymentResponse
5, // 24: ark.v1.ArkService.FinalizePayment:output_type -> ark.v1.FinalizePaymentResponse
@@ -1737,7 +1756,7 @@ var file_ark_v1_service_proto_depIdxs = []int32{
20, // 27: ark.v1.ArkService.Ping:output_type -> ark.v1.PingResponse
22, // 28: ark.v1.ArkService.Faucet:output_type -> ark.v1.FaucetResponse
24, // 29: ark.v1.ArkService.ListVtxos:output_type -> ark.v1.ListVtxosResponse
27, // 30: ark.v1.ArkService.GetPubkey:output_type -> ark.v1.GetPubkeyResponse
27, // 30: ark.v1.ArkService.GetInfo:output_type -> ark.v1.GetInfoResponse
22, // [22:31] is the sub-list for method output_type
13, // [13:22] is the sub-list for method input_type
13, // [13:13] is the sub-list for extension type_name
@@ -2064,7 +2083,7 @@ func file_ark_v1_service_proto_init() {
}
}
file_ark_v1_service_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetPubkeyRequest); i {
switch v := v.(*GetInfoRequest); i {
case 0:
return &v.state
case 1:
@@ -2076,7 +2095,7 @@ func file_ark_v1_service_proto_init() {
}
}
file_ark_v1_service_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetPubkeyResponse); i {
switch v := v.(*GetInfoResponse); i {
case 0:
return &v.state
case 1:

View File

@@ -334,20 +334,20 @@ func local_request_ArkService_ListVtxos_0(ctx context.Context, marshaler runtime
}
func request_ArkService_GetPubkey_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetPubkeyRequest
func request_ArkService_GetInfo_0(ctx context.Context, marshaler runtime.Marshaler, client ArkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetInfoRequest
var metadata runtime.ServerMetadata
msg, err := client.GetPubkey(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
msg, err := client.GetInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ArkService_GetPubkey_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetPubkeyRequest
func local_request_ArkService_GetInfo_0(ctx context.Context, marshaler runtime.Marshaler, server ArkServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetInfoRequest
var metadata runtime.ServerMetadata
msg, err := server.GetPubkey(ctx, &protoReq)
msg, err := server.GetInfo(ctx, &protoReq)
return msg, metadata, err
}
@@ -540,7 +540,7 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("GET", pattern_ArkService_GetPubkey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("GET", pattern_ArkService_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
@@ -548,12 +548,12 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux,
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/GetPubkey", runtime.WithHTTPPathPattern("/v1/pubkey"))
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ark.v1.ArkService/GetInfo", runtime.WithHTTPPathPattern("/v1/info"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ArkService_GetPubkey_0(annotatedContext, inboundMarshaler, server, req, pathParams)
resp, md, err := local_request_ArkService_GetInfo_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
@@ -561,7 +561,7 @@ func RegisterArkServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux,
return
}
forward_ArkService_GetPubkey_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_ArkService_GetInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
@@ -782,25 +782,25 @@ func RegisterArkServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("GET", pattern_ArkService_GetPubkey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("GET", pattern_ArkService_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/GetPubkey", runtime.WithHTTPPathPattern("/v1/pubkey"))
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ark.v1.ArkService/GetInfo", runtime.WithHTTPPathPattern("/v1/info"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ArkService_GetPubkey_0(annotatedContext, inboundMarshaler, client, req, pathParams)
resp, md, err := request_ArkService_GetInfo_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_ArkService_GetPubkey_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_ArkService_GetInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
@@ -824,7 +824,7 @@ var (
pattern_ArkService_ListVtxos_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "vtxos", "address"}, ""))
pattern_ArkService_GetPubkey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "pubkey"}, ""))
pattern_ArkService_GetInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "info"}, ""))
)
var (
@@ -844,5 +844,5 @@ var (
forward_ArkService_ListVtxos_0 = runtime.ForwardResponseMessage
forward_ArkService_GetPubkey_0 = runtime.ForwardResponseMessage
forward_ArkService_GetInfo_0 = runtime.ForwardResponseMessage
)

View File

@@ -26,7 +26,7 @@ type ArkServiceClient interface {
Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error)
Faucet(ctx context.Context, in *FaucetRequest, opts ...grpc.CallOption) (*FaucetResponse, error)
ListVtxos(ctx context.Context, in *ListVtxosRequest, opts ...grpc.CallOption) (*ListVtxosResponse, error)
GetPubkey(ctx context.Context, in *GetPubkeyRequest, opts ...grpc.CallOption) (*GetPubkeyResponse, error)
GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error)
}
type arkServiceClient struct {
@@ -132,9 +132,9 @@ func (c *arkServiceClient) ListVtxos(ctx context.Context, in *ListVtxosRequest,
return out, nil
}
func (c *arkServiceClient) GetPubkey(ctx context.Context, in *GetPubkeyRequest, opts ...grpc.CallOption) (*GetPubkeyResponse, error) {
out := new(GetPubkeyResponse)
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/GetPubkey", in, out, opts...)
func (c *arkServiceClient) GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error) {
out := new(GetInfoResponse)
err := c.cc.Invoke(ctx, "/ark.v1.ArkService/GetInfo", in, out, opts...)
if err != nil {
return nil, err
}
@@ -153,7 +153,7 @@ type ArkServiceServer interface {
Ping(context.Context, *PingRequest) (*PingResponse, error)
Faucet(context.Context, *FaucetRequest) (*FaucetResponse, error)
ListVtxos(context.Context, *ListVtxosRequest) (*ListVtxosResponse, error)
GetPubkey(context.Context, *GetPubkeyRequest) (*GetPubkeyResponse, error)
GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error)
}
// UnimplementedArkServiceServer should be embedded to have forward compatible implementations.
@@ -184,8 +184,8 @@ func (UnimplementedArkServiceServer) Faucet(context.Context, *FaucetRequest) (*F
func (UnimplementedArkServiceServer) ListVtxos(context.Context, *ListVtxosRequest) (*ListVtxosResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListVtxos not implemented")
}
func (UnimplementedArkServiceServer) GetPubkey(context.Context, *GetPubkeyRequest) (*GetPubkeyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPubkey not implemented")
func (UnimplementedArkServiceServer) GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetInfo not implemented")
}
// UnsafeArkServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -346,20 +346,20 @@ func _ArkService_ListVtxos_Handler(srv interface{}, ctx context.Context, dec fun
return interceptor(ctx, in, info, handler)
}
func _ArkService_GetPubkey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPubkeyRequest)
func _ArkService_GetInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetInfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ArkServiceServer).GetPubkey(ctx, in)
return srv.(ArkServiceServer).GetInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ark.v1.ArkService/GetPubkey",
FullMethod: "/ark.v1.ArkService/GetInfo",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ArkServiceServer).GetPubkey(ctx, req.(*GetPubkeyRequest))
return srv.(ArkServiceServer).GetInfo(ctx, req.(*GetInfoRequest))
}
return interceptor(ctx, in, info, handler)
}
@@ -400,8 +400,8 @@ var ArkService_ServiceDesc = grpc.ServiceDesc{
Handler: _ArkService_ListVtxos_Handler,
},
{
MethodName: "GetPubkey",
Handler: _ArkService_GetPubkey_Handler,
MethodName: "GetInfo",
Handler: _ArkService_GetInfo_Handler,
},
},
Streams: []grpc.StreamDesc{

View File

@@ -37,6 +37,12 @@ func main() {
log.Infof("round lifetime must be a multiple of 512, %d -> %d", setLifetime, cfg.RoundLifetime)
}
if cfg.ExitDelay%512 != 0 {
setExitDelay := cfg.ExitDelay
cfg.ExitDelay = cfg.ExitDelay - (cfg.ExitDelay % 512)
log.Infof("exit delay must be a multiple of 512, %d -> %d", setExitDelay, cfg.ExitDelay)
}
appConfig := &appconfig.Config{
DbType: cfg.DbType,
DbDir: cfg.DbDir,
@@ -48,6 +54,7 @@ func main() {
WalletAddr: cfg.WalletAddr,
MinRelayFee: cfg.MinRelayFee,
RoundLifetime: cfg.RoundLifetime,
ExitDelay: cfg.ExitDelay,
}
svc, err := grpcservice.NewService(svcConfig, appConfig)
if err != nil {

View File

@@ -43,6 +43,7 @@ type Config struct {
WalletAddr string
MinRelayFee uint64
RoundLifetime int64
ExitDelay int64
repo ports.RepoManager
svc application.Service
@@ -96,8 +97,8 @@ func (c *Config) Validate() error {
return err
}
// round life time must be a multiple of 512
if c.RoundLifetime <= 0 || c.RoundLifetime%512 != 0 {
return fmt.Errorf("invalid round lifetime, must be greater than 0 and a multiple of 512")
if c.RoundLifetime < 512 || c.RoundLifetime%512 != 0 {
return fmt.Errorf("invalid round lifetime, must be greater or equal than 512 and a multiple of 512")
}
seq, err := common.BIP68Encode(uint(c.RoundLifetime))
if err != nil {
@@ -113,6 +114,10 @@ func (c *Config) Validate() error {
return fmt.Errorf("invalid round lifetime, must be a multiple of 512")
}
if c.ExitDelay < 512 || c.ExitDelay%512 != 0 {
return fmt.Errorf("invalid exit delay, must be greater or equal than 512 and a multiple of 512")
}
return nil
}
@@ -165,7 +170,7 @@ func (c *Config) txBuilderService() error {
case "dummy":
svc = txbuilderdummy.NewTxBuilder(c.wallet, net)
case "covenant":
svc = txbuilder.NewTxBuilder(c.wallet, net, c.RoundLifetime)
svc = txbuilder.NewTxBuilder(c.wallet, net, c.RoundLifetime, c.ExitDelay)
default:
err = fmt.Errorf("unknown tx builder type")
}
@@ -214,7 +219,7 @@ func (c *Config) schedulerService() error {
func (c *Config) appService() error {
net := c.mainChain()
svc, err := application.NewService(
c.Network, net, c.RoundInterval, c.RoundLifetime, c.MinRelayFee,
c.Network, net, c.RoundInterval, c.RoundLifetime, c.ExitDelay, c.MinRelayFee,
c.wallet, c.repo, c.txBuilder, c.scanner, c.scheduler,
)
if err != nil {

View File

@@ -24,6 +24,7 @@ type Config struct {
LogLevel int
MinRelayFee uint64
RoundLifetime int64
ExitDelay int64
}
var (
@@ -40,6 +41,7 @@ var (
Network = "NETWORK"
MinRelayFee = "MIN_RELAY_FEE"
RoundLifetime = "ROUND_LIFETIME"
ExitDelay = "EXIT_DELAY"
defaultDatadir = common.AppDataDir("arkd", false)
defaultRoundInterval = 10
@@ -53,6 +55,7 @@ var (
defaultLogLevel = 5
defaultMinRelayFee = 30
defaultRoundLifetime = 512
defaultExitDelay = 512
)
func LoadConfig() (*Config, error) {
@@ -71,6 +74,7 @@ func LoadConfig() (*Config, error) {
viper.SetDefault(Network, defaultNetwork)
viper.SetDefault(RoundLifetime, defaultRoundLifetime)
viper.SetDefault(MinRelayFee, defaultMinRelayFee)
viper.SetDefault(ExitDelay, defaultExitDelay)
net, err := getNetwork()
if err != nil {
@@ -95,6 +99,7 @@ func LoadConfig() (*Config, error) {
Network: net,
MinRelayFee: viper.GetUint64(MinRelayFee),
RoundLifetime: viper.GetInt64(RoundLifetime),
ExitDelay: viper.GetInt64(ExitDelay),
}, nil
}

View File

@@ -37,7 +37,7 @@ type Service interface {
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
UpdatePaymentStatus(ctx context.Context, id string) error
ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, error)
GetPubkey(ctx context.Context) (string, error)
GetInfo(ctx context.Context) (string, int64, int64, error)
}
type service struct {
@@ -47,6 +47,7 @@ type service struct {
roundLifetime int64
roundInterval int64
minRelayFee uint64
exitDelay int64
wallet ports.WalletService
repoManager ports.RepoManager
@@ -62,7 +63,7 @@ type service struct {
func NewService(
network common.Network, onchainNetwork network.Network,
roundInterval, roundLifetime int64, minRelayFee uint64,
roundInterval, roundLifetime int64, exitDelay int64, minRelayFee uint64,
walletSvc ports.WalletService, repoManager ports.RepoManager,
builder ports.TxBuilder, scanner ports.BlockchainScanner,
scheduler ports.SchedulerService,
@@ -81,7 +82,7 @@ func NewService(
svc := &service{
network, onchainNetwork, pubkey,
roundLifetime, roundInterval, minRelayFee,
roundLifetime, roundInterval, minRelayFee, exitDelay,
walletSvc, repoManager, builder, scanner, sweeper,
paymentRequests, forfeitTxs, eventsCh,
}
@@ -218,8 +219,8 @@ func (s *service) GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.
return s.repoManager.Rounds().GetRoundWithTxid(ctx, poolTxid)
}
func (s *service) GetPubkey(ctx context.Context) (string, error) {
return hex.EncodeToString(s.pubkey.SerializeCompressed()), nil
func (s *service) GetInfo(ctx context.Context) (string, int64, int64, error) {
return hex.EncodeToString(s.pubkey.SerializeCompressed()), s.roundLifetime, s.exitDelay, nil
}
func (s *service) start() {

View File

@@ -2,7 +2,6 @@ package application
import (
"context"
"encoding/hex"
"fmt"
"time"
@@ -10,7 +9,6 @@ import (
"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/psetv2"
)
@@ -326,17 +324,6 @@ func (s *sweeper) findSweepableOutputs(
newNodesToCheck = append(newNodesToCheck, children...)
continue
}
// if the node is a leaf, the vtxos outputs should added as onchain outputs if they are not swept yet
vtxoExpiration, sweepInput, err := s.leafToSweepInput(ctx, blocktime, node)
if err != nil {
return nil, err
}
if sweepInput != nil {
expirationTime = vtxoExpiration
sweepInputs = []ports.SweepInput{*sweepInput}
}
}
if _, ok := sweepableOutputs[expirationTime]; !ok {
@@ -351,62 +338,6 @@ func (s *sweeper) findSweepableOutputs(
return sweepableOutputs, nil
}
func (s *sweeper) leafToSweepInput(ctx context.Context, txBlocktime int64, node tree.Node) (int64, *ports.SweepInput, error) {
pset, err := psetv2.NewPsetFromBase64(node.Tx)
if err != nil {
return -1, nil, err
}
vtxo, err := extractVtxoOutpoint(pset)
if err != nil {
return -1, nil, err
}
fromRepo, err := s.repoManager.Vtxos().GetVtxos(ctx, []domain.VtxoKey{*vtxo})
if err != nil {
return -1, nil, err
}
if len(fromRepo) == 0 {
return -1, nil, fmt.Errorf("vtxo not found")
}
if fromRepo[0].Swept {
return -1, nil, nil
}
if fromRepo[0].Redeemed {
return -1, nil, nil
}
// if the vtxo is not swept or redeemed, add it to the onchain outputs
pubKeyBytes, err := hex.DecodeString(fromRepo[0].Pubkey)
if err != nil {
return -1, nil, err
}
pubKey, err := secp256k1.ParsePubKey(pubKeyBytes)
if err != nil {
return -1, nil, err
}
sweepLeaf, lifetime, err := s.builder.GetLeafSweepClosure(node, pubKey)
if err != nil {
return -1, nil, err
}
sweepInput := ports.SweepInput{
InputArgs: psetv2.InputArgs{
Txid: vtxo.Txid,
TxIndex: vtxo.VOut,
},
SweepLeaf: *sweepLeaf,
Amount: fromRepo[0].Amount,
}
return txBlocktime + lifetime, &sweepInput, nil
}
func (s *sweeper) nodeToSweepInputs(parentBlocktime int64, node tree.Node) (int64, []ports.SweepInput, error) {
pset, err := psetv2.NewPsetFromBase64(node.Tx)
if err != nil {
@@ -543,14 +474,14 @@ func containsTree(tr0 tree.CongestionTree, tr1 tree.CongestionTree) (bool, error
// given a congestion tree input, searches and returns the sweep leaf and its lifetime in seconds
func extractSweepLeaf(input psetv2.Input) (sweepLeaf *psetv2.TapLeafScript, lifetime int64, err error) {
for _, leaf := range input.TapLeafScript {
isSweep, _, seconds, err := tree.DecodeSweepScript(leaf.Script)
closure := &tree.CSVSigClosure{}
valid, err := closure.Decode(leaf.Script)
if err != nil {
return nil, 0, err
}
if isSweep {
lifetime = int64(seconds)
if valid && closure.Seconds > uint(lifetime) {
sweepLeaf = &leaf
break
lifetime = int64(closure.Seconds)
}
}

View File

@@ -24,6 +24,5 @@ type TxBuilder interface {
wallet WalletService,
inputs []SweepInput,
) (signedSweepTx string, err error)
GetLeafSweepClosure(node tree.Node, userPubKey *secp256k1.PublicKey) (*psetv2.TapLeafScript, int64, error)
GetVtxoScript(userPubkey, aspPubkey *secp256k1.PublicKey) ([]byte, error)
}

View File

@@ -224,7 +224,7 @@ func (s *service) EstimateFees(
}
if len(in.TapLeafScript) == 1 {
isSweep, _, _, err := tree.DecodeSweepScript(in.TapLeafScript[0].Script)
isSweep, err := (&tree.CSVSigClosure{}).Decode(in.TapLeafScript[0].Script)
if err != nil {
return 0, err
}

View File

@@ -24,12 +24,13 @@ type txBuilder struct {
wallet ports.WalletService
net *network.Network
roundLifetime int64 // in seconds
exitDelay int64 // in seconds
}
func NewTxBuilder(
wallet ports.WalletService, net network.Network, roundLifetime int64,
wallet ports.WalletService, net network.Network, roundLifetime int64, exitDelay int64,
) ports.TxBuilder {
return &txBuilder{wallet, &net, roundLifetime}
return &txBuilder{wallet, &net, roundLifetime, exitDelay}
}
func (b *txBuilder) GetVtxoScript(userPubkey, aspPubkey *secp256k1.PublicKey) ([]byte, error) {
@@ -113,7 +114,7 @@ func (b *txBuilder) BuildPoolTx(
// This is safe as the memory allocated for `craftCongestionTree` is freed
// only after `BuildPoolTx` returns.
treeFactoryFn, sharedOutputScript, sharedOutputAmount, err := craftCongestionTree(
b.net.AssetID, aspPubkey, payments, minRelayFee, b.roundLifetime,
b.net.AssetID, aspPubkey, payments, minRelayFee, b.roundLifetime, b.exitDelay,
)
if err != nil {
return
@@ -148,60 +149,31 @@ func (b *txBuilder) BuildPoolTx(
return
}
func (b *txBuilder) GetLeafSweepClosure(
node tree.Node, userPubKey *secp256k1.PublicKey,
) (*psetv2.TapLeafScript, int64, error) {
if !node.Leaf {
return nil, 0, fmt.Errorf("node is not a leaf")
}
pset, err := psetv2.NewPsetFromBase64(node.Tx)
if err != nil {
return nil, 0, err
}
input := pset.Inputs[0]
sweepLeaf, lifetime, err := extractSweepLeaf(input)
if err != nil {
return nil, 0, err
}
// craft the vtxo taproot tree
vtxoScript, err := tree.VtxoScript(userPubKey)
if err != nil {
return nil, 0, err
}
vtxoTaprootTree := taproot.AssembleTaprootScriptTree(
*vtxoScript,
sweepLeaf.TapElementsLeaf,
)
proofIndex := vtxoTaprootTree.LeafProofIndex[sweepLeaf.TapHash()]
proof := vtxoTaprootTree.LeafMerkleProofs[proofIndex]
return &psetv2.TapLeafScript{
TapElementsLeaf: proof.TapElementsLeaf,
ControlBlock: proof.ToControlBlock(sweepLeaf.ControlBlock.InternalKey),
}, lifetime, nil
}
func (b *txBuilder) getLeafScriptAndTree(
userPubkey, aspPubkey *secp256k1.PublicKey,
) ([]byte, *taproot.IndexedElementsTapScriptTree, error) {
redeemClosure, err := tree.VtxoScript(userPubkey)
redeemClosure := &tree.CSVSigClosure{
Pubkey: userPubkey,
Seconds: uint(b.exitDelay),
}
redeemLeaf, err := redeemClosure.Leaf()
if err != nil {
return nil, nil, err
}
sweepClosure, err := tree.SweepScript(aspPubkey, uint(b.roundLifetime))
forfeitClosure := &tree.ForfeitClosure{
Pubkey: userPubkey,
AspPubkey: aspPubkey,
}
forfeitLeaf, err := forfeitClosure.Leaf()
if err != nil {
return nil, nil, err
}
taprootTree := taproot.AssembleTaprootScriptTree(
*redeemClosure, *sweepClosure,
*redeemLeaf, *forfeitLeaf,
)
root := taprootTree.RootNode.TapHash()
@@ -471,9 +443,25 @@ func (b *txBuilder) createForfeitTxs(
return nil, err
}
var forfeitProof *taproot.TapscriptElementsProof
for _, proof := range vtxoTaprootTree.LeafMerkleProofs {
isForfeit, err := (&tree.ForfeitClosure{}).Decode(proof.Script)
if !isForfeit || err != nil {
continue
}
forfeitProof = &proof
break
}
if forfeitProof == nil {
return nil, fmt.Errorf("forfeit proof not found")
}
for _, connector := range connectors {
txs, err := craftForfeitTxs(
connector, vtxo, vtxoTaprootTree, vtxoScript, aspScript,
connector, vtxo, *forfeitProof, vtxoScript, aspScript,
)
if err != nil {
return nil, err
@@ -485,24 +473,3 @@ func (b *txBuilder) createForfeitTxs(
}
return forfeitTxs, nil
}
// given a congestion tree input, searches and returns the sweep leaf and its lifetime in seconds
func extractSweepLeaf(input psetv2.Input) (sweepLeaf *psetv2.TapLeafScript, lifetime int64, err error) {
for _, leaf := range input.TapLeafScript {
isSweep, _, seconds, err := tree.DecodeSweepScript(leaf.Script)
if err != nil {
return nil, 0, err
}
if isSweep {
lifetime = int64(seconds)
sweepLeaf = &leaf
break
}
}
if sweepLeaf == nil {
return nil, 0, fmt.Errorf("sweep leaf not found")
}
return sweepLeaf, lifetime, nil
}

View File

@@ -23,6 +23,7 @@ const (
testingKey = "0218d5ca8b58797b7dbd65c075dd7ba7784b3f38ab71b1a5a8e3f94ba0257654a6"
minRelayFee = uint64(30)
roundLifetime = int64(1209344)
exitDelay = int64(512)
)
var (
@@ -44,7 +45,7 @@ func TestMain(m *testing.M) {
}
func TestBuildPoolTx(t *testing.T) {
builder := txbuilder.NewTxBuilder(wallet, network.Liquid, roundLifetime)
builder := txbuilder.NewTxBuilder(wallet, network.Liquid, roundLifetime, exitDelay)
fixtures, err := parsePoolTxFixtures()
require.NoError(t, err)
@@ -79,7 +80,7 @@ func TestBuildPoolTx(t *testing.T) {
}
func TestBuildForfeitTxs(t *testing.T) {
builder := txbuilder.NewTxBuilder(wallet, network.Liquid, 1209344)
builder := txbuilder.NewTxBuilder(wallet, network.Liquid, 1209344, exitDelay)
fixtures, err := parseForfeitTxsFixtures()
require.NoError(t, err)

View File

@@ -13,7 +13,7 @@ import (
func craftForfeitTxs(
connectorTx *psetv2.Pset,
vtxo domain.Vtxo,
vtxoTaprootTree *taproot.IndexedElementsTapScriptTree,
vtxoForfeitTapleaf taproot.TapscriptElementsProof,
vtxoScript, aspScript []byte,
) (forfeitTxs []string, err error) {
connectors, prevouts := getConnectorInputs(connectorTx)
@@ -66,11 +66,9 @@ func craftForfeitTxs(
unspendableKey := tree.UnspendableKey()
for _, proof := range vtxoTaprootTree.LeafMerkleProofs {
tapScript := psetv2.NewTapLeafScript(proof, unspendableKey)
if err := updater.AddInTapLeafScript(1, tapScript); err != nil {
return nil, err
}
tapScript := psetv2.NewTapLeafScript(vtxoForfeitTapleaf, unspendableKey)
if err := updater.AddInTapLeafScript(1, tapScript); err != nil {
return nil, err
}
connectorAmount, err := elementsutil.ValueFromBytes(connectorPrevout.Value)

View File

@@ -33,55 +33,56 @@ func sweepTransaction(
for i, input := range sweepInputs {
leaf := input.SweepLeaf
isSweep, _, lifetime, err := tree.DecodeSweepScript(leaf.Script)
sweepClosure := &tree.CSVSigClosure{}
isSweep, err := sweepClosure.Decode(leaf.Script)
if err != nil {
return nil, err
}
if isSweep {
amount += input.Amount
if err := updater.AddInputs([]psetv2.InputArgs{input.InputArgs}); err != nil {
return nil, err
}
if err := updater.AddInTapLeafScript(i, leaf); err != nil {
return nil, err
}
assetHash, err := elementsutil.AssetHashToBytes(lbtc)
if err != nil {
return nil, err
}
value, err := elementsutil.ValueToBytes(input.Amount)
if err != nil {
return nil, err
}
root := leaf.ControlBlock.RootHash(leaf.Script)
taprootKey := taproot.ComputeTaprootOutputKey(leaf.ControlBlock.InternalKey, root)
script, err := taprootOutputScript(taprootKey)
if err != nil {
return nil, err
}
witnessUtxo := transaction.NewTxOutput(assetHash, value, script)
if err := updater.AddInWitnessUtxo(i, witnessUtxo); err != nil {
return nil, err
}
sequence, err := common.BIP68EncodeAsNumber(lifetime)
if err != nil {
return nil, err
}
updater.Pset.Inputs[i].Sequence = sequence
continue
if !isSweep {
return nil, fmt.Errorf("invalid sweep script")
}
return nil, fmt.Errorf("invalid sweep script")
amount += input.Amount
if err := updater.AddInputs([]psetv2.InputArgs{input.InputArgs}); err != nil {
return nil, err
}
if err := updater.AddInTapLeafScript(i, leaf); err != nil {
return nil, err
}
assetHash, err := elementsutil.AssetHashToBytes(lbtc)
if err != nil {
return nil, err
}
value, err := elementsutil.ValueToBytes(input.Amount)
if err != nil {
return nil, err
}
root := leaf.ControlBlock.RootHash(leaf.Script)
taprootKey := taproot.ComputeTaprootOutputKey(leaf.ControlBlock.InternalKey, root)
script, err := taprootOutputScript(taprootKey)
if err != nil {
return nil, err
}
witnessUtxo := transaction.NewTxOutput(assetHash, value, script)
if err := updater.AddInWitnessUtxo(i, witnessUtxo); err != nil {
return nil, err
}
sequence, err := common.BIP68EncodeAsNumber(sweepClosure.Seconds)
if err != nil {
return nil, err
}
updater.Pset.Inputs[i].Sequence = sequence
continue
}
ctx := context.Background()

View File

@@ -22,6 +22,7 @@ type node struct {
asset string
feeSats uint64
roundLifetime int64
exitDelay int64
_inputTaprootKey *secp256k1.PublicKey
_inputTaprootTree *taproot.IndexedElementsTapScriptTree
@@ -130,7 +131,12 @@ func (n *node) getWitnessData() (
return n._inputTaprootKey, n._inputTaprootTree, nil
}
sweepClosure, err := tree.SweepScript(n.sweepKey, uint(n.roundLifetime))
sweepClosure := &tree.CSVSigClosure{
Pubkey: n.sweepKey,
Seconds: uint(n.roundLifetime),
}
sweepLeaf, err := sweepClosure.Leaf()
if err != nil {
return nil, nil, err
}
@@ -141,12 +147,18 @@ func (n *node) getWitnessData() (
return nil, nil, err
}
branchTaprootScript := tree.BranchScript(
taprootKey, nil, n.getAmount(), 0,
)
unrollClosure := &tree.UnrollClosure{
LeftKey: taprootKey,
LeftAmount: n.getAmount(),
}
unrollLeaf, err := unrollClosure.Leaf()
if err != nil {
return nil, nil, err
}
branchTaprootTree := taproot.AssembleTaprootScriptTree(
branchTaprootScript, *sweepClosure,
*unrollLeaf, *sweepLeaf,
)
root := branchTaprootTree.RootNode.TapHash()
@@ -173,12 +185,21 @@ func (n *node) getWitnessData() (
leftAmount := n.left.getAmount() + n.feeSats
rightAmount := n.right.getAmount() + n.feeSats
branchTaprootLeaf := tree.BranchScript(
leftKey, rightKey, leftAmount, rightAmount,
)
unrollClosure := &tree.UnrollClosure{
LeftKey: leftKey,
LeftAmount: leftAmount,
RightKey: rightKey,
RightAmount: rightAmount,
}
unrollLeaf, err := unrollClosure.Leaf()
if err != nil {
return nil, nil, err
}
branchTaprootTree := taproot.AssembleTaprootScriptTree(
branchTaprootLeaf, *sweepClosure,
*unrollLeaf, *sweepLeaf,
)
root := branchTaprootTree.RootNode.TapHash()
@@ -200,11 +221,6 @@ func (n *node) getVtxoWitnessData() (
return nil, nil, fmt.Errorf("cannot call vtxoWitness on a non-leaf node")
}
sweepClosure, err := tree.SweepScript(n.sweepKey, uint(n.roundLifetime))
if err != nil {
return nil, nil, err
}
key, err := hex.DecodeString(n.receivers[0].Pubkey)
if err != nil {
return nil, nil, err
@@ -215,14 +231,28 @@ func (n *node) getVtxoWitnessData() (
return nil, nil, err
}
vtxoLeaf, err := tree.VtxoScript(pubkey)
redeemClosure := &tree.CSVSigClosure{
Pubkey: pubkey,
Seconds: uint(n.exitDelay),
}
redeemLeaf, err := redeemClosure.Leaf()
if err != nil {
return nil, nil, err
}
forfeitClosure := &tree.ForfeitClosure{
Pubkey: pubkey,
AspPubkey: n.sweepKey,
}
forfeitLeaf, err := forfeitClosure.Leaf()
if err != nil {
return nil, nil, err
}
// TODO: add forfeit path
leafTaprootTree := taproot.AssembleTaprootScriptTree(
*vtxoLeaf, *sweepClosure,
*redeemLeaf, *forfeitLeaf,
)
root := leafTaprootTree.RootNode.TapHash()
@@ -357,14 +387,14 @@ func (n *node) createFinalCongestionTree() treeFactory {
func craftCongestionTree(
asset string, aspPublicKey *secp256k1.PublicKey,
payments []domain.Payment, feeSatsPerNode uint64, roundLifetime int64,
payments []domain.Payment, feeSatsPerNode uint64, roundLifetime int64, exitDelay int64,
) (
buildCongestionTree treeFactory,
sharedOutputScript []byte, sharedOutputAmount uint64, err error,
) {
receivers := getOffchainReceivers(payments)
root, err := createPartialCongestionTree(
receivers, aspPublicKey, asset, feeSatsPerNode, roundLifetime,
receivers, aspPublicKey, asset, feeSatsPerNode, roundLifetime, exitDelay,
)
if err != nil {
return
@@ -391,6 +421,7 @@ func createPartialCongestionTree(
asset string,
feeSatsPerNode uint64,
roundLifetime int64,
exitDelay int64,
) (root *node, err error) {
if len(receivers) == 0 {
return nil, fmt.Errorf("no receivers provided")
@@ -404,6 +435,7 @@ func createPartialCongestionTree(
asset: asset,
feeSats: feeSatsPerNode,
roundLifetime: roundLifetime,
exitDelay: exitDelay,
}
nodes = append(nodes, leafNode)
}

View File

@@ -178,14 +178,16 @@ func (h *handler) ListVtxos(ctx context.Context, req *arkv1.ListVtxosRequest) (*
}, nil
}
func (h *handler) GetPubkey(ctx context.Context, req *arkv1.GetPubkeyRequest) (*arkv1.GetPubkeyResponse, error) {
pubkey, err := h.svc.GetPubkey(ctx)
func (h *handler) GetInfo(ctx context.Context, req *arkv1.GetInfoRequest) (*arkv1.GetInfoResponse, error) {
pubkey, lifetime, delay, err := h.svc.GetInfo(ctx)
if err != nil {
return nil, err
}
return &arkv1.GetPubkeyResponse{
Pubkey: pubkey,
return &arkv1.GetInfoResponse{
Pubkey: pubkey,
Lifetime: lifetime,
ExitDelay: delay,
}, nil
}