Skip to content

Commit

Permalink
Merge pull request #796 from lightninglabs/multisig-demo
Browse files Browse the repository at this point in the history
[psbt saga part 4/4]: Multisig demo
  • Loading branch information
guggero authored Mar 21, 2024
2 parents d2070a4 + 5a029ee commit 5cac1e4
Show file tree
Hide file tree
Showing 22 changed files with 1,817 additions and 993 deletions.
15 changes: 12 additions & 3 deletions itest/addrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,11 +554,20 @@ func sendProof(t *harnessTest, src, dst *tapdHarness,
}, defaultWaitTimeout)
require.NoError(t.t, waitErr)

t.Logf("Importing proof %x", proofResp.RawProofFile)
return importProof(t, dst, proofResp.RawProofFile, genInfo.GenesisPoint)
}

// importProof manually imports a proof using the development only ImportProof
// RPC.
func importProof(t *harnessTest, dst *tapdHarness, rawFile []byte,
genesisPoint string) *tapdevrpc.ImportProofResponse {

t.Logf("Importing proof %x", rawFile)

ctxb := context.Background()
importResp, err := dst.ImportProof(ctxb, &tapdevrpc.ImportProofRequest{
ProofFile: proofResp.RawProofFile,
GenesisPoint: genInfo.GenesisPoint,
ProofFile: rawFile,
GenesisPoint: genesisPoint,
})
require.NoError(t.t, err)

Expand Down
9 changes: 4 additions & 5 deletions itest/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -956,9 +956,6 @@ func assertProofReveals(t *testing.T, expected *taprpc.Asset,
actual *taprpc.DecodedProof) {

if actual.GenesisReveal != nil {
actual.GenesisReveal.GenesisBaseReveal.Version =
expected.AssetGenesis.Version

require.Equal(
t, expected.AssetGenesis,
actual.GenesisReveal.GenesisBaseReveal,
Expand All @@ -977,7 +974,6 @@ func AssertAssetGenesis(t *testing.T, expected, actual *taprpc.GenesisInfo) {
require.Equal(t, expected.MetaHash, actual.MetaHash)
require.Equal(t, expected.AssetId, actual.AssetId)
require.Equal(t, expected.OutputIndex, actual.OutputIndex)
require.Equal(t, expected.Version, actual.Version)
}

// AssertBalanceByID asserts that the balance of a single asset,
Expand Down Expand Up @@ -1619,7 +1615,10 @@ func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,

for _, balance := range assetIDBalances.AssetBalances {
for _, rpcAsset := range allAssets {
if balance.AssetGenesis.Name == rpcAsset.AssetGenesis.Name {
balanceGen := balance.AssetGenesis
targetGen := rpcAsset.AssetGenesis

if balanceGen.Name == targetGen.Name {
require.Equal(
t, balance.Balance, rpcAsset.Amount,
)
Expand Down
8 changes: 4 additions & 4 deletions itest/burn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ func testBurnAssets(t *harnessTest) {
// Preparation: We derive a couple of keys, so we can spread out our
// assets over several outputs, which we are going to use for the first
// couple of test cases.
scriptKey1, anchorInternalKeyDesc1 := deriveKeys(t.t, t.tapd)
scriptKey2, anchorInternalKeyDesc2 := deriveKeys(t.t, t.tapd)
scriptKey3, anchorInternalKeyDesc3 := deriveKeys(t.t, t.tapd)
scriptKey4, _ := deriveKeys(t.t, t.tapd)
scriptKey1, anchorInternalKeyDesc1 := DeriveKeys(t.t, t.tapd)
scriptKey2, anchorInternalKeyDesc2 := DeriveKeys(t.t, t.tapd)
scriptKey3, anchorInternalKeyDesc3 := DeriveKeys(t.t, t.tapd)
scriptKey4, _ := DeriveKeys(t.t, t.tapd)

// We create the following outputs:
// anchor index 0 (anchor internal key 1):
Expand Down
41 changes: 41 additions & 0 deletions itest/loadtest/config.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package loadtest

import (
"fmt"
"time"

"github.com/btcsuite/btcd/chaincfg"
"github.com/jessevdk/go-flags"
"github.com/lightninglabs/taproot-assets/taprpc"
)
Expand All @@ -21,6 +23,7 @@ const (
// User defines the config options for a user in the network.
type User struct {
Tapd *TapConfig `group:"tapd" namespace:"tapd"`
Lnd *LndConfig `group:"lnd" namespace:"lnd"`
}

// TapConfig are the main parameters needed for identifying and creating a grpc
Expand All @@ -34,6 +37,17 @@ type TapConfig struct {
MacPath string `long:"macpath" description:"Path to tapd's macaroon file"`
}

// LndConfig are the main parameters needed for identifying and creating a grpc
// client to a lnd subsystem.
type LndConfig struct {
Name string `long:"name" description:"the name of the lnd instance"`
Host string `long:"host" description:"the host to connect to"`
Port int `long:"port" description:"the port to connect to"`

TLSPath string `long:"tlspath" description:"Path to lnd's TLS certificate, leave empty if TLS is disabled"`
MacPath string `long:"macpath" description:"Path to tlnd's macaroon file"`
}

// BitcoinConfig defines exported config options for the connection to the
// btcd/bitcoind backend.
type BitcoinConfig struct {
Expand All @@ -56,6 +70,9 @@ type Config struct {
// Bob is the configuration for the secondary user in the network.
Bob *User `group:"bob" namespace:"bob" description:"bob related configuration"`

// Network is the network that the nodes are connected to.
Network string `long:"network" description:"the network the nodes are connected to" choice:"regtest" choice:"testnet" choice:"mainnet"`

// Bitcoin is the configuration for the bitcoin backend.
Bitcoin *BitcoinConfig `group:"bitcoin" namespace:"bitcoin" long:"bitcoin" description:"bitcoin client configuration"`

Expand Down Expand Up @@ -96,6 +113,7 @@ func DefaultConfig() Config {
Name: "bob",
},
},
Network: "regtest",
BatchSize: 100,
NumSends: 50,
NumAssets: 1, // We only mint collectibles.
Expand Down Expand Up @@ -140,3 +158,26 @@ func ValidateConfig(cfg Config) (*Config, error) {
// TODO (positiveblue): add validation logic.
return &cfg, nil
}

// networkParams parses the global network flag into a chaincfg.Params.
func networkParams(network string) (*chaincfg.Params, error) {
switch network {
case "mainnet":
return &chaincfg.MainNetParams, nil

case "testnet":
return &chaincfg.TestNet3Params, nil

case "regtest":
return &chaincfg.RegressionNetParams, nil

case "simnet":
return &chaincfg.SimNetParams, nil

case "signet":
return &chaincfg.SigNetParams, nil

default:
return nil, fmt.Errorf("unknown network: %v", network)
}
}
4 changes: 4 additions & 0 deletions itest/loadtest/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ var loadTestCases = []testCase{
name: "send",
fn: sendTest,
},
{
name: "multisig",
fn: multisigTest,
},
}

// TestPerformance executes the configured performance tests.
Expand Down
35 changes: 1 addition & 34 deletions itest/loadtest/mint_batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ import (
"math/rand"
"strings"
"testing"
"time"

"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/itest"
"github.com/lightninglabs/taproot-assets/taprpc"
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
unirpc "github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightninglabs/taproot-assets/universe"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -166,36 +164,5 @@ func mintTest(t *testing.T, ctx context.Context, cfg *Config) {
})
require.True(t, correctOp)

_, err = bob.AddFederationServer(
ctx, &unirpc.AddFederationServerRequest{
Servers: []*unirpc.UniverseFederationServer{
{
Host: aliceHost,
},
},
},
)
if err != nil {
// Only fail the test for other errors than duplicate universe
// errors, as we might have already added the server in a
// previous run.
require.ErrorContains(
t, err, universe.ErrDuplicateUniverse.Error(),
)

// If we've already added the server in a previous run, we'll
// just need to kick off a sync (as that would otherwise be done
// by adding the server request already).
_, err := bob.SyncUniverse(ctx, &unirpc.SyncRequest{
UniverseHost: aliceHost,
SyncMode: unirpc.UniverseSyncMode_SYNC_ISSUANCE_ONLY,
})
require.NoError(t, err)
}

require.Eventually(t, func() bool {
return itest.AssertUniverseStateEqual(
t, alice, bob,
)
}, minterTimeout, time.Second)
itest.SyncUniverses(ctx, t, alice, bob, aliceHost, cfg.TestTimeout)
}
35 changes: 35 additions & 0 deletions itest/loadtest/multisig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package loadtest

import (
"context"
"fmt"
"testing"

"github.com/lightninglabs/taproot-assets/itest"
"github.com/stretchr/testify/require"
)

// multisigTest tests that we can use multi signature on all levels of the
// Taproot Assets Protocol. This includes the BTC level, the asset level and the
// group key level.
func multisigTest(t *testing.T, ctx context.Context, cfg *Config) {
// Start by initializing all our client connections.
aliceTapd, bobTapd, bitcoinClient := initClients(t, ctx, cfg)

params, err := networkParams(cfg.Network)
require.NoError(t, err)

var (
aliceLnd = aliceTapd.lnd
bobLnd = bobTapd.lnd
)

aliceHost := fmt.Sprintf(
"%s:%d", aliceTapd.cfg.Host, aliceTapd.cfg.Port,
)

itest.MultiSigTest(
t, ctx, aliceTapd, bobTapd, aliceHost, bitcoinClient, aliceLnd,
bobLnd, params, cfg.TestTimeout,
)
}
61 changes: 58 additions & 3 deletions itest/loadtest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
"github.com/lightninglabs/taproot-assets/taprpc/tapdevrpc"
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
Expand All @@ -35,6 +36,7 @@ var (

type rpcClient struct {
cfg *TapConfig
lnd *rpc.HarnessRPC
taprpc.TaprootAssetsClient
assetwalletrpc.AssetWalletClient
tapdevrpc.TapDevClient
Expand Down Expand Up @@ -102,12 +104,12 @@ func initClients(t *testing.T, ctx context.Context,
cfg *Config) (*rpcClient, *rpcClient, *rpcclient.Client) {

// Create tapd clients.
alice := getTapClient(t, ctx, cfg.Alice.Tapd)
alice := getTapClient(t, ctx, cfg.Alice.Tapd, cfg.Alice.Lnd)

_, err := alice.GetInfo(ctx, &taprpc.GetInfoRequest{})
require.NoError(t, err)

bob := getTapClient(t, ctx, cfg.Bob.Tapd)
bob := getTapClient(t, ctx, cfg.Bob.Tapd, cfg.Bob.Lnd)

_, err = bob.GetInfo(ctx, &taprpc.GetInfoRequest{})
require.NoError(t, err)
Expand All @@ -129,7 +131,7 @@ func initClients(t *testing.T, ctx context.Context,
}

func getTapClient(t *testing.T, ctx context.Context,
cfg *TapConfig) *rpcClient {
cfg *TapConfig, lndCfg *LndConfig) *rpcClient {

creds := credentials.NewTLS(&tls.Config{})
if cfg.TLSPath != "" {
Expand Down Expand Up @@ -169,6 +171,8 @@ func getTapClient(t *testing.T, ctx context.Context,
conn, err := grpc.DialContext(ctx, svrAddr, opts...)
require.NoError(t, err)

lnd := getLndClient(t, ctx, lndCfg)

assetsClient := taprpc.NewTaprootAssetsClient(conn)
assetWalletClient := assetwalletrpc.NewAssetWalletClient(conn)
devClient := tapdevrpc.NewTapDevClient(conn)
Expand All @@ -178,6 +182,7 @@ func getTapClient(t *testing.T, ctx context.Context,

client := &rpcClient{
cfg: cfg,
lnd: lnd,
TaprootAssetsClient: assetsClient,
AssetWalletClient: assetWalletClient,
TapDevClient: devClient,
Expand All @@ -194,6 +199,56 @@ func getTapClient(t *testing.T, ctx context.Context,
return client
}

func getLndClient(t *testing.T, ctx context.Context,
cfg *LndConfig) *rpc.HarnessRPC {

creds := credentials.NewTLS(&tls.Config{})
if cfg.TLSPath != "" {
// Load the certificate file now, if specified.
tlsCert, err := os.ReadFile(cfg.TLSPath)
require.NoError(t, err)

cp := x509.NewCertPool()
ok := cp.AppendCertsFromPEM(tlsCert)
require.True(t, ok)

creds = credentials.NewClientTLSFromCert(cp, "")
}

// Create a dial options array.
opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithDefaultCallOptions(tap.MaxMsgReceiveSize),
}

if cfg.MacPath != "" {
macBytes, err := os.ReadFile(cfg.MacPath)
require.NoError(t, err)

mac := &macaroon.Macaroon{}
err = mac.UnmarshalBinary(macBytes)
require.NoError(t, err)

macCred, err := macaroons.NewMacaroonCredential(mac)
require.NoError(t, err)

opts = append(opts, grpc.WithPerRPCCredentials(macCred))
}

svrAddr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
conn, err := grpc.DialContext(ctx, svrAddr, opts...)
require.NoError(t, err)

client := rpc.NewHarnessRPC(ctx, t, conn, cfg.Name)

t.Cleanup(func() {
err := conn.Close()
require.NoError(t, err)
})

return client
}

func getBitcoinConn(t *testing.T, cfg *BitcoinConfig) *rpcclient.Client {
var (
rpcCert []byte
Expand Down
Loading

0 comments on commit 5cac1e4

Please sign in to comment.