Skip to content

Commit

Permalink
tapgarden: propogate taptree sibling for batch key
Browse files Browse the repository at this point in the history
  • Loading branch information
jharveyb committed Jan 12, 2024
1 parent 987274e commit dc692d5
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 16 deletions.
11 changes: 7 additions & 4 deletions tapgarden/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/commitment"
Expand Down Expand Up @@ -104,7 +105,9 @@ func (m *MintingBatch) validateGroupAnchor(s *Seedling) error {

// MintingOutputKey derives the output key that once mined, will commit to the
// Taproot asset root, thereby creating the set of included assets.
func (m *MintingBatch) MintingOutputKey() (*btcec.PublicKey, []byte, error) {
func (m *MintingBatch) MintingOutputKey(
sibling *chainhash.Hash) (*btcec.PublicKey, []byte, error) {

if m.mintingPubKey != nil {
return m.mintingPubKey, m.taprootAssetScriptRoot, nil
}
Expand All @@ -113,7 +116,7 @@ func (m *MintingBatch) MintingOutputKey() (*btcec.PublicKey, []byte, error) {
return nil, nil, fmt.Errorf("no asset commitment present")
}

taprootAssetScriptRoot := m.RootAssetCommitment.TapscriptRoot(nil)
taprootAssetScriptRoot := m.RootAssetCommitment.TapscriptRoot(sibling)

m.taprootAssetScriptRoot = taprootAssetScriptRoot[:]
m.mintingPubKey = txscript.ComputeTaprootOutputKey(
Expand All @@ -125,8 +128,8 @@ func (m *MintingBatch) MintingOutputKey() (*btcec.PublicKey, []byte, error) {

// genesisScript returns the script that should be placed in the minting output
// within the genesis transaction.
func (m *MintingBatch) genesisScript() ([]byte, error) {
mintingOutputKey, _, err := m.MintingOutputKey()
func (m *MintingBatch) genesisScript(sibling *chainhash.Hash) ([]byte, error) {
mintingOutputKey, _, err := m.MintingOutputKey(sibling)
if err != nil {
return nil, err
}
Expand Down
26 changes: 24 additions & 2 deletions tapgarden/caretaker.go
Original file line number Diff line number Diff line change
Expand Up @@ -665,10 +665,30 @@ func (b *BatchCaretaker) stateStep(currentState BatchState) (BatchState, error)

b.cfg.Batch.RootAssetCommitment = tapCommitment

// Fetch the optional Tapscript tree for this batch, and convert
// it to a TapHash.
batchKey := asset.ToSerialized(b.cfg.Batch.BatchKey.PubKey)
batchTapscriptTree, err := b.cfg.TreeStore.LoadTapscriptTree(
ctx, batchKey,
)
if err != asset.TreeNotFound {
return 0, err
}

var tapSibling *chainhash.Hash
if batchTapscriptTree != nil {
tapSibling, err = tapscript.TapTreeToSibling(
*batchTapscriptTree,
)
if err != nil {
return 0, err
}
}

// With the commitment Taproot Asset root SMT constructed, we'll
// map that into the tapscript root we'll insert into the
// genesis transaction.
genesisScript, err := b.cfg.Batch.genesisScript()
genesisScript, err := b.cfg.Batch.genesisScript(tapSibling)
if err != nil {
return 0, fmt.Errorf("unable to create genesis "+
"script: %v", err)
Expand Down Expand Up @@ -766,7 +786,9 @@ func (b *BatchCaretaker) stateStep(currentState BatchState) (BatchState, error)
//
// TODO(roasbeef): re-run during the broadcast phase to ensure
// it's fully imported?
mintingOutputKey, tapRoot, err := b.cfg.Batch.MintingOutputKey()
mintingOutputKey, tapRoot, err := b.cfg.Batch.MintingOutputKey(
nil,
)
if err != nil {
return 0, err
}
Expand Down
28 changes: 18 additions & 10 deletions tapgarden/planter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type mintingTestHarness struct {

store tapgarden.MintingStore

treeStore *asset.MockTapscriptTreeStore

keyRing *tapgarden.MockKeyRing

genSigner *tapgarden.MockGenSigner
Expand Down Expand Up @@ -99,6 +101,7 @@ func newMintingTestHarness(t *testing.T, store tapgarden.MintingStore,
return &mintingTestHarness{
T: t,
store: store,
treeStore: asset.NewMockTapscriptTreeStore(),
ticker: ticker.NewForce(interval),
wallet: tapgarden.NewMockWalletAnchor(),
chain: tapgarden.NewMockChainBridge(),
Expand All @@ -125,6 +128,7 @@ func (t *mintingTestHarness) refreshChainPlanter() {
Wallet: t.wallet,
ChainBridge: t.chain,
Log: t.store,
TreeStore: t.treeStore,
KeyRing: t.keyRing,
GenSigner: t.genSigner,
GenTxBuilder: t.genTxBuilder,
Expand Down Expand Up @@ -276,7 +280,7 @@ func (t *mintingTestHarness) assertFinalizeBatch(wg *sync.WaitGroup,
// progressCaretaker uses the mock interfaces to progress a caretaker from start
// to TX confirmation.
func (t *mintingTestHarness) progressCaretaker(
seedlings []*tapgarden.Seedling) func() {
seedlings []*tapgarden.Seedling, batchSibling *chainhash.Hash) func() {

// Assert that the caretaker has requested a genesis TX to be funded.
_ = t.assertGenesisTxFunded()
Expand All @@ -294,7 +298,7 @@ func (t *mintingTestHarness) progressCaretaker(

// We should now transition to the next state where we'll attempt to
// sign this PSBT packet generated above.
t.assertGenesisPsbtFinalized()
t.assertGenesisPsbtFinalized(batchSibling)

// With the PSBT packet finalized for the caretaker, we should now
// receive a request to publish a transaction followed by a
Expand Down Expand Up @@ -625,7 +629,9 @@ func (t *mintingTestHarness) assertSeedlingsMatchSprouts(

// assertGenesisPsbtFinalized asserts that a request to finalize the genesis
// transaction has been requested by a caretaker.
func (t *mintingTestHarness) assertGenesisPsbtFinalized() {
func (t *mintingTestHarness) assertGenesisPsbtFinalized(
sibling *chainhash.Hash) {

t.Helper()

// Ensure that a request to finalize the PSBt has come across.
Expand All @@ -649,7 +655,7 @@ func (t *mintingTestHarness) assertGenesisPsbtFinalized() {

// The minting key of the batch should match the public key
// that was inserted into the wallet.
batchKey, _, err := pendingBatch.MintingOutputKey()
batchKey, _, err := pendingBatch.MintingOutputKey(sibling)
require.NoError(t, err)

importedKey, err := fn.RecvOrTimeout(
Expand Down Expand Up @@ -790,7 +796,7 @@ func testBasicAssetCreation(t *mintingTestHarness) {

// We should now transition to the next state where we'll attempt to
// sign this PSBT packet generated above.
t.assertGenesisPsbtFinalized()
t.assertGenesisPsbtFinalized(nil)

// With the PSBT packet finalized for the caretaker, we should now
// receive a request to publish a transaction followed by a
Expand Down Expand Up @@ -892,7 +898,7 @@ func testMintingTicker(t *mintingTestHarness) {

// We should now transition to the next state where we'll attempt to
// sign this PSBT packet generated above.
t.assertGenesisPsbtFinalized()
t.assertGenesisPsbtFinalized(nil)

// With the PSBT packet finalized for the caretaker, we should now
// receive a request to publish a transaction followed by a
Expand Down Expand Up @@ -1028,7 +1034,7 @@ func testMintingCancelFinalize(t *mintingTestHarness) {

// We should now transition to the next state where we'll attempt to
// sign this PSBT packet generated above.
t.assertGenesisPsbtFinalized()
t.assertGenesisPsbtFinalized(nil)

// With the PSBT packet finalized for the caretaker, we should now
// receive a request to publish a transaction followed by a
Expand Down Expand Up @@ -1136,7 +1142,7 @@ func testFinalizeBatch(t *mintingTestHarness) {
t.finalizeBatch(&wg, respChan)
batchCount++

_ = t.progressCaretaker(seedlings)
_ = t.progressCaretaker(seedlings, nil)
caretakerCount++

t.assertFinalizeBatch(&wg, respChan, "")
Expand All @@ -1160,7 +1166,7 @@ func testFinalizeBatch(t *mintingTestHarness) {
t.finalizeBatch(&wg, respChan)
batchCount++

sendConfNtfn := t.progressCaretaker(seedlings)
sendConfNtfn := t.progressCaretaker(seedlings, nil)
caretakerCount++

// Trigger the confirmation event, which should cause the caretaker to
Expand Down Expand Up @@ -1190,14 +1196,16 @@ func testFinalizeBatch(t *mintingTestHarness) {
t.finalizeBatch(&wg, respChan)
batchCount++

sendConfNtfn = t.progressCaretaker(seedlings)
sendConfNtfn = t.progressCaretaker(seedlings, nil)
sendConfNtfn()

t.assertFinalizeBatch(&wg, respChan, "")
t.assertNoError()
t.assertNoPendingBatch()
t.assertNumCaretakersActive(caretakerCount)
t.assertLastBatchState(batchCount, tapgarden.BatchStateFinalized)

// TODO(jhb): add finalize with tapscript root
}

// mintingStoreTestCase is used to programmatically run a series of test cases
Expand Down

0 comments on commit dc692d5

Please sign in to comment.