Skip to content

Commit

Permalink
Merge pull request #771 from Roasbeef/v0-3-3-branch
Browse files Browse the repository at this point in the history
release: create v0.3.3 branch
  • Loading branch information
Roasbeef authored Jan 26, 2024
2 parents 564795a + d36e844 commit f7c543d
Show file tree
Hide file tree
Showing 71 changed files with 4,443 additions and 1,221 deletions.
50 changes: 50 additions & 0 deletions fn/func.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ func All[T any](xs []T, pred func(T) bool) bool {
return true
}

// AllMapItems returns true if the passed predicate returns true for all items
// in the map.
func AllMapItems[T any, K comparable](xs map[K]T, pred func(T) bool) bool {
for i := range xs {
if !pred(xs[i]) {
return false
}
}

return true
}

// Any returns true if the passed predicate returns true for any item in the
// slice.
func Any[T any](xs []T, pred func(T) bool) bool {
Expand All @@ -148,6 +160,30 @@ func None[T any](xs []T, pred func(T) bool) bool {
return !Any(xs, pred)
}

// AnyMapItem returns true if the passed predicate returns true for any item in
// the map.
func AnyMapItem[T any, K comparable](xs map[K]T, pred func(T) bool) bool {
for i := range xs {
if pred(xs[i]) {
return true
}
}

return false
}

// NotAny returns true if the passed predicate returns false for all items in
// the slice.
func NotAny[T any](xs []T, pred func(T) bool) bool {
return !Any(xs, pred)
}

// NotAnyMapItem returns true if the passed predicate returns false for all
// items in the map.
func NotAnyMapItem[T any, K comparable](xs map[K]T, pred func(T) bool) bool {
return !AnyMapItem(xs, pred)
}

// Count returns the number of items in the slice that match the predicate.
func Count[T any](xs []T, pred func(T) bool) int {
var count int
Expand All @@ -161,6 +197,20 @@ func Count[T any](xs []T, pred func(T) bool) int {
return count
}

// CountMapItems returns the number of items in the map that match the
// predicate.
func CountMapItems[T any, K comparable](xs map[K]T, pred func(T) bool) int {
var count int

for i := range xs {
if pred(xs[i]) {
count++
}
}

return count
}

// First returns the first item in the slice that matches the predicate, or an
// error if none matches.
func First[T any](xs []*T, pred func(*T) bool) (*T, error) {
Expand Down
28 changes: 21 additions & 7 deletions fn/iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ package fn
// This function can be used instead of the normal range loop to ensure that a
// loop scoping bug isn't introduced.
func ForEachErr[T any](s []T, f func(T) error) error {
for _, item := range s {
item := item

if err := f(item); err != nil {
for i := range s {
if err := f(s[i]); err != nil {
return err
}
}
Expand All @@ -22,9 +20,17 @@ func ForEachErr[T any](s []T, f func(T) error) error {
// This can be used to ensure that any normal for-loop don't run into bugs due
// to loop variable scoping.
func ForEach[T any](items []T, f func(T)) {
for _, item := range items {
item := item
f(item)
for i := range items {
f(items[i])
}
}

// ForEachMapItem is a generic implementation of a for-each (map with side
// effects). This can be used to ensure that any normal for-loop don't run into
// bugs due to loop variable scoping.
func ForEachMapItem[T any, K comparable](items map[K]T, f func(T)) {
for i := range items {
f(items[i])
}
}

Expand All @@ -38,6 +44,14 @@ func Enumerate[T any](items []T, f func(int, T)) {
}
}

// EnumerateMap is a generic enumeration function. The closure will be called
// for each key and item in the passed-in map.
func EnumerateMap[T any, K comparable](items map[K]T, f func(K, T)) {
for key := range items {
f(key, items[key])
}
}

// MakeSlice is a generic function shorthand for making a slice out of a set
// of elements. This can be used to avoid having to specify the type of the
// slice as well as the types of the elements.
Expand Down
117 changes: 90 additions & 27 deletions itest/addrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
tap "github.com/lightninglabs/taproot-assets"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/internal/test"
"github.com/lightninglabs/taproot-assets/proof"
"github.com/lightninglabs/taproot-assets/tappsbt"
"github.com/lightninglabs/taproot-assets/taprpc"
wrpc "github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc"
Expand Down Expand Up @@ -40,10 +41,6 @@ func testAddresses(t *harnessTest) {
// assets made above.
secondTapd := setupTapdHarness(
t.t, t, t.lndHarness.Bob, t.universeServer,
func(params *tapdHarnessParams) {
params.startupSyncNode = t.tapd
params.startupSyncNumAssets = len(rpcAssets)
},
)
defer func() {
require.NoError(t.t, secondTapd.stop(!*noDelete))
Expand Down Expand Up @@ -79,12 +76,6 @@ func testAddresses(t *harnessTest) {
// Eventually the event should be marked as confirmed.
AssertAddrEvent(t.t, secondTapd, addr, 1, statusConfirmed)

// To complete the transfer, we'll export the proof from the
// sender and import it into the receiver for each asset set.
sendProof(
t, t.tapd, secondTapd, addr.ScriptKey, a.AssetGenesis,
)

// Make sure we have imported and finalized all proofs.
AssertNonInteractiveRecvComplete(t.t, secondTapd, idx+1)

Expand Down Expand Up @@ -175,10 +166,6 @@ func testMultiAddress(t *harnessTest) {
alice := t.tapd
bob := setupTapdHarness(
t.t, t, t.lndHarness.Bob, t.universeServer,
func(params *tapdHarnessParams) {
params.startupSyncNode = alice
params.startupSyncNumAssets = len(rpcAssets)
},
)
defer func() {
require.NoError(t.t, bob.stop(!*noDelete))
Expand All @@ -195,7 +182,12 @@ func testMultiAddress(t *harnessTest) {
func testAddressAssetSyncer(t *harnessTest) {
// We'll kick off the test by making a new node, without hooking it up
// to any existing Universe server.
bob := setupTapdHarness(t.t, t, t.lndHarness.Bob, nil)
bob := setupTapdHarness(
t.t, t, t.lndHarness.Bob, t.universeServer,
func(params *tapdHarnessParams) {
params.noDefaultUniverseSync = true
},
)
defer func() {
require.NoError(t.t, bob.stop(!*noDelete))
}()
Expand Down Expand Up @@ -321,8 +313,9 @@ func testAddressAssetSyncer(t *harnessTest) {
restartBobNoUniSync := func(disableSyncer bool) {
require.NoError(t.t, bob.stop(!*noDelete))
bob = setupTapdHarness(
t.t, t, t.lndHarness.Bob, nil,
t.t, t, t.lndHarness.Bob, t.universeServer,
func(params *tapdHarnessParams) {
params.noDefaultUniverseSync = true
params.addrAssetSyncerDisable = disableSyncer
},
)
Expand Down Expand Up @@ -436,21 +429,18 @@ func runMultiSendTest(ctxt context.Context, t *harnessTest, alice,

// In order to force a split, we don't try to send the full asset.
const sendAmt = 100
var bobAddresses []*taprpc.Addr
bobAddr1, err := bob.NewAddr(ctxt, &taprpc.NewAddrRequest{
AssetId: genInfo.AssetId,
Amt: sendAmt,
})
require.NoError(t.t, err)
bobAddresses = append(bobAddresses, bobAddr1)
AssertAddrCreated(t.t, bob, mintedAsset, bobAddr1)

bobAddr2, err := bob.NewAddr(ctxt, &taprpc.NewAddrRequest{
AssetId: genInfo.AssetId,
Amt: sendAmt,
})
require.NoError(t.t, err)
bobAddresses = append(bobAddresses, bobAddr2)
AssertAddrCreated(t.t, bob, mintedAsset, bobAddr2)

// To test that Alice can also receive to multiple addresses in a single
Expand Down Expand Up @@ -492,14 +482,6 @@ func runMultiSendTest(ctxt context.Context, t *harnessTest, alice,
// this point, so the status should go to completed directly.
AssertAddrEventByStatus(t.t, alice, statusCompleted, numRuns*2)

// To complete the transfer, we'll export the proof from the sender and
// import it into the receiver for each asset set. This should not be
// necessary for the sends to Alice, as she is both the sender and
// receiver and should detect the local proof once it's written to disk.
for i := range bobAddresses {
sendProof(t, alice, bob, bobAddresses[i].ScriptKey, genInfo)
}

// Make sure we have imported and finalized all proofs.
AssertNonInteractiveRecvComplete(t.t, bob, numRuns*2)
AssertNonInteractiveRecvComplete(t.t, alice, numRuns*2)
Expand Down Expand Up @@ -531,6 +513,8 @@ func runMultiSendTest(ctxt context.Context, t *harnessTest, alice,
require.NoError(t.t, err)
}

// sendProof manually exports a proof from the given source node and imports it
// using the development only ImportProof RPC on the destination node.
func sendProof(t *harnessTest, src, dst *tapdHarness, scriptKey []byte,
genInfo *taprpc.GenesisInfo) *tapdevrpc.ImportProofResponse {

Expand Down Expand Up @@ -562,6 +546,85 @@ func sendProof(t *harnessTest, src, dst *tapdHarness, scriptKey []byte,
return importResp
}

// sendProofUniRPC manually exports a proof from the given source node and
// imports it using the universe related InsertProof RPC on the destination
// node.
func sendProofUniRPC(t *harnessTest, src, dst *tapdHarness, scriptKey []byte,
genInfo *taprpc.GenesisInfo) *unirpc.AssetProofResponse {

ctxb := context.Background()

var proofResp *taprpc.ProofFile
waitErr := wait.NoError(func() error {
resp, err := src.ExportProof(ctxb, &taprpc.ExportProofRequest{
AssetId: genInfo.AssetId,
ScriptKey: scriptKey,
})
if err != nil {
return err
}

proofResp = resp
return nil
}, defaultWaitTimeout)
require.NoError(t.t, waitErr)

t.Logf("Importing proof %x using InsertProof", proofResp.RawProofFile)

f := proof.File{}
err := f.Decode(bytes.NewReader(proofResp.RawProofFile))
require.NoError(t.t, err)

lastProof, err := f.LastProof()
require.NoError(t.t, err)

var lastProofBytes bytes.Buffer
err = lastProof.Encode(&lastProofBytes)
require.NoError(t.t, err)
asset := lastProof.Asset

proofType := universe.ProofTypeTransfer
if asset.IsGenesisAsset() {
proofType = universe.ProofTypeIssuance
}

uniID := universe.Identifier{
AssetID: asset.ID(),
ProofType: proofType,
}
if asset.GroupKey != nil {
uniID.GroupKey = &asset.GroupKey.GroupPubKey
}

rpcUniID, err := tap.MarshalUniID(uniID)
require.NoError(t.t, err)

outpoint := &unirpc.Outpoint{
HashStr: lastProof.AnchorTx.TxHash().String(),
Index: int32(lastProof.InclusionProof.OutputIndex),
}

importResp, err := dst.InsertProof(ctxb, &unirpc.AssetProof{
Key: &unirpc.UniverseKey{
Id: rpcUniID,
LeafKey: &unirpc.AssetKey{
Outpoint: &unirpc.AssetKey_Op{
Op: outpoint,
},
ScriptKey: &unirpc.AssetKey_ScriptKeyBytes{
ScriptKeyBytes: scriptKey,
},
},
},
AssetLeaf: &unirpc.AssetLeaf{
Proof: lastProofBytes.Bytes(),
},
})
require.NoError(t.t, err)

return importResp
}

// sendAssetsToAddr spends the given input asset and sends the amount specified
// in the address to the Taproot output derived from the address.
func sendAssetsToAddr(t *harnessTest, sender *tapdHarness,
Expand Down
4 changes: 2 additions & 2 deletions itest/aperture_harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type ApertureHarness struct {

// NewApertureHarness creates a new instance of the aperture service. It returns
// a harness which includes useful values for testing.
func NewApertureHarness(t *testing.T, port int) ApertureHarness {
func NewApertureHarness(t *testing.T, port int) *ApertureHarness {
// Create a temporary directory for the aperture service to use.
baseDir := filepath.Join(t.TempDir(), "aperture")
err := os.MkdirAll(baseDir, os.ModePerm)
Expand Down Expand Up @@ -55,7 +55,7 @@ func NewApertureHarness(t *testing.T, port int) ApertureHarness {
}
service := aperture.NewAperture(cfg)

return ApertureHarness{
return &ApertureHarness{
ListenAddr: listenAddr,
Service: service,
}
Expand Down
2 changes: 1 addition & 1 deletion itest/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ func AssertBalanceByID(t *testing.T, client taprpc.TaprootAssetsClient,
}

require.True(t, ok)
require.Equal(t, uint64(amt), uint64(balance.Balance))
require.Equal(t, amt, balance.Balance)
}

// AssertBalanceByGroup asserts that the balance of a single asset group
Expand Down
4 changes: 0 additions & 4 deletions itest/collectible_split_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ func testCollectibleSend(t *harnessTest) {
// serve as the node which'll receive the assets.
secondTapd := setupTapdHarness(
t.t, t, t.lndHarness.Bob, t.universeServer,
func(params *tapdHarnessParams) {
params.startupSyncNode = t.tapd
params.startupSyncNumAssets = len(rpcAssets)
},
)
defer func() {
require.NoError(t.t, secondTapd.stop(!*noDelete))
Expand Down
12 changes: 4 additions & 8 deletions itest/full_value_split_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ func testFullValueSend(t *harnessTest) {
// serve as the node which'll receive the assets.
secondTapd := setupTapdHarness(
t.t, t, t.lndHarness.Bob, t.universeServer,
func(params *tapdHarnessParams) {
params.startupSyncNode = t.tapd
params.startupSyncNumAssets = len(rpcAssets)
},
)
defer func() {
require.NoError(t.t, secondTapd.stop(!*noDelete))
Expand Down Expand Up @@ -88,8 +84,8 @@ func runFullValueSendTests(ctxt context.Context, t *harnessTest, alice,
[]uint64{0, fullAmount}, senderTransferIdx,
senderTransferIdx+1,
)
_ = sendProof(
t, alice, bob, receiverAddr.ScriptKey, genInfo,
AssertNonInteractiveRecvComplete(
t.t, bob, senderTransferIdx+1,
)
senderTransferIdx++
} else {
Expand All @@ -108,8 +104,8 @@ func runFullValueSendTests(ctxt context.Context, t *harnessTest, alice,
genInfo.AssetId, []uint64{0, fullAmount},
receiverTransferIdx, receiverTransferIdx+1,
)
_ = sendProof(
t, bob, alice, receiverAddr.ScriptKey, genInfo,
AssertNonInteractiveRecvComplete(
t.t, alice, receiverTransferIdx+1,
)
receiverTransferIdx++
}
Expand Down
Loading

0 comments on commit f7c543d

Please sign in to comment.