Skip to content

Commit 4f738f4

Browse files
committed
Merge branch 'send-to-self'
2 parents 2b90fad + 57eb1c0 commit 4f738f4

19 files changed

+1049
-525
lines changed

api/firmware/backup_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package firmware
1616

1717
import (
18+
"bytes"
1819
"testing"
1920

2021
"github.com/stretchr/testify/require"
@@ -23,7 +24,7 @@ import (
2324
func TestSimulatorBackups(t *testing.T) {
2425
const seedLen = 32
2526
const testName = "test wallet name"
26-
testSimulatorsAfterPairing(t, func(t *testing.T, device *Device) {
27+
testSimulatorsAfterPairing(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
2728
t.Helper()
2829
require.NoError(t, device.SetDeviceName(testName))
2930

api/firmware/bip85_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package firmware
1616

1717
import (
18+
"bytes"
1819
"encoding/hex"
1920
"testing"
2021

@@ -27,7 +28,7 @@ func TestSimulatorBIP85AppBip39(t *testing.T) {
2728
}
2829

2930
func TestSimulatorBIP85AppLN(t *testing.T) {
30-
testInitializedSimulators(t, func(t *testing.T, device *Device) {
31+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
3132
t.Helper()
3233
entropy, err := device.BIP85AppLN()
3334
require.NoError(t, err)

api/firmware/btc.go

+6
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ type BTCTx struct {
284284
func (device *Device) BTCSign(
285285
coin messages.BTCCoin,
286286
scriptConfigs []*messages.BTCScriptConfigWithKeypath,
287+
outputScriptConfigs []*messages.BTCScriptConfigWithKeypath,
287288
tx *BTCTx,
288289
formatUnit messages.BTCSignInitRequest_FormatUnit,
289290
) ([][]byte, map[int][]byte, error) {
@@ -310,6 +311,10 @@ func (device *Device) BTCSign(
310311
return nil, nil, UnsupportedError("9.21.0")
311312
}
312313

314+
if len(outputScriptConfigs) > 0 && !device.version.AtLeast(semver.NewSemVer(9, 22, 0)) {
315+
return nil, nil, UnsupportedError("9.22.0")
316+
}
317+
313318
signatures := make([][]byte, len(tx.Inputs))
314319
next, err := device.queryBtcSign(&messages.Request{
315320
Request: &messages.Request_BtcSignInit{
@@ -322,6 +327,7 @@ func (device *Device) BTCSign(
322327
Locktime: tx.Locktime,
323328
FormatUnit: formatUnit,
324329
ContainsSilentPaymentOutputs: containsSilentPaymentOutputs,
330+
OutputScriptConfigs: outputScriptConfigs,
325331
}}})
326332
if err != nil {
327333
return nil, nil, err

api/firmware/btc_test.go

+228-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package firmware
1717

1818
import (
19+
"bytes"
1920
"errors"
2021
"testing"
2122

@@ -36,6 +37,7 @@ import (
3637

3738
const hardenedKeyStart = 0x80000000
3839

40+
//nolint:unparam
3941
func mustOutpoint(s string) *wire.OutPoint {
4042
outPoint, err := wire.NewOutPointFromString(s)
4143
if err != nil {
@@ -68,7 +70,7 @@ func TestNewXPub(t *testing.T) {
6870
}
6971

7072
func TestBTCXpub(t *testing.T) {
71-
testInitializedSimulators(t, func(t *testing.T, device *Device) {
73+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
7274
t.Helper()
7375
xpub, err := device.BTCXPub(messages.BTCCoin_TBTC, []uint32{
7476
49 + hardenedKeyStart,
@@ -80,9 +82,10 @@ func TestBTCXpub(t *testing.T) {
8082
})
8183
}
8284

83-
func TestBTCAddress(t *testing.T) {
84-
testInitializedSimulators(t, func(t *testing.T, device *Device) {
85+
func TestSimulatorBTCAddress(t *testing.T) {
86+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
8587
t.Helper()
88+
// TBTC, P2WPKH
8689
address, err := device.BTCAddress(
8790
messages.BTCCoin_TBTC,
8891
[]uint32{
@@ -97,6 +100,43 @@ func TestBTCAddress(t *testing.T) {
97100
)
98101
require.NoError(t, err)
99102
require.Equal(t, "tb1qq064dxjgl9h9wzgsmzy6t6306qew42w9ka02u3", address)
103+
104+
// BTC, P2WPKH
105+
address, err = device.BTCAddress(
106+
messages.BTCCoin_BTC,
107+
[]uint32{
108+
84 + hardenedKeyStart,
109+
0 + hardenedKeyStart,
110+
0 + hardenedKeyStart,
111+
1,
112+
10,
113+
},
114+
NewBTCScriptConfigSimple(messages.BTCScriptConfig_P2WPKH),
115+
false,
116+
)
117+
require.NoError(t, err)
118+
require.Equal(t, "bc1qcq0ceq9vs24g4tnkkx3k2rry9j44r74huc3d7s", address)
119+
120+
// RBTC, P2WPKH
121+
address, err = device.BTCAddress(
122+
messages.BTCCoin_RBTC,
123+
[]uint32{
124+
84 + hardenedKeyStart,
125+
1 + hardenedKeyStart,
126+
0 + hardenedKeyStart,
127+
1,
128+
10,
129+
},
130+
NewBTCScriptConfigSimple(messages.BTCScriptConfig_P2WPKH),
131+
false,
132+
)
133+
// Regtest (RBTC) support added in v9.21.0
134+
if device.Version().AtLeast(semver.NewSemVer(9, 21, 0)) {
135+
require.NoError(t, err)
136+
require.Equal(t, "bcrt1qq064dxjgl9h9wzgsmzy6t6306qew42w955k8tc", address)
137+
} else {
138+
require.Error(t, err)
139+
}
100140
})
101141
}
102142

@@ -114,7 +154,7 @@ func simulatorPub(t *testing.T, device *Device, keypath ...uint32) *btcec.Public
114154
}
115155

116156
func TestSimulatorBTCSignMessage(t *testing.T) {
117-
testInitializedSimulators(t, func(t *testing.T, device *Device) {
157+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
118158
t.Helper()
119159
coin := messages.BTCCoin_BTC
120160
keypath := []uint32{49 + hardenedKeyStart, 0 + hardenedKeyStart, 0 + hardenedKeyStart, 0, 10}
@@ -206,7 +246,7 @@ func TestSimulatorBTCXPub(t *testing.T) {
206246
})
207247
}
208248

209-
func TestSimulatorBTCAddress(t *testing.T) {
249+
func TestBTCAddress(t *testing.T) {
210250
testConfigurations(t, func(t *testing.T, env *testEnv) {
211251
t.Helper()
212252
expected := "mocked-address"
@@ -341,7 +381,7 @@ func makeTaprootOutput(t *testing.T, pubkey *btcec.PublicKey) (*btcec.PublicKey,
341381

342382
// Test signing; all inputs are BIP86 Taproot keyspends.
343383
func TestSimulatorBTCSignTaprootKeySpend(t *testing.T) {
344-
testInitializedSimulators(t, func(t *testing.T, device *Device) {
384+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
345385
t.Helper()
346386
coin := messages.BTCCoin_BTC
347387
accountKeypath := []uint32{86 + hardenedKeyStart, 0 + hardenedKeyStart, 0 + hardenedKeyStart}
@@ -385,6 +425,7 @@ func TestSimulatorBTCSignTaprootKeySpend(t *testing.T) {
385425
_, _, err := device.BTCSign(
386426
coin,
387427
scriptConfigs,
428+
nil,
388429
&BTCTx{
389430
Version: 2,
390431
Inputs: []*BTCTxInput{
@@ -431,7 +472,7 @@ func TestSimulatorBTCSignTaprootKeySpend(t *testing.T) {
431472

432473
// Test signing; mixed input types (p2wpkh, p2wpkh-p2sh, p2tr)
433474
func TestSimulatorBTCSignMixed(t *testing.T) {
434-
testInitializedSimulators(t, func(t *testing.T, device *Device) {
475+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
435476
t.Helper()
436477
coin := messages.BTCCoin_BTC
437478
changeKeypath := []uint32{86 + hardenedKeyStart, 0 + hardenedKeyStart, 0 + hardenedKeyStart, 1, 0}
@@ -513,6 +554,7 @@ func TestSimulatorBTCSignMixed(t *testing.T) {
513554
_, _, err := device.BTCSign(
514555
coin,
515556
scriptConfigs,
557+
nil,
516558
&BTCTx{
517559
Version: 2,
518560
Inputs: []*BTCTxInput{
@@ -573,7 +615,7 @@ func TestSimulatorBTCSignMixed(t *testing.T) {
573615
// Test that we can send to a silent payment output (generated by the BitBox) and verify the
574616
// corresponding DLEQ proof on the host that the output was generated correctly.
575617
func TestSimulatorBTCSignSilentPayment(t *testing.T) {
576-
testInitializedSimulators(t, func(t *testing.T, device *Device) {
618+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
577619
t.Helper()
578620
coin := messages.BTCCoin_BTC
579621
accountKeypath := []uint32{86 + hardenedKeyStart, 0 + hardenedKeyStart, 0 + hardenedKeyStart}
@@ -614,6 +656,7 @@ func TestSimulatorBTCSignSilentPayment(t *testing.T) {
614656
Keypath: accountKeypath,
615657
},
616658
},
659+
nil,
617660
&BTCTx{
618661
Version: 2,
619662
Inputs: []*BTCTxInput{
@@ -671,3 +714,180 @@ func TestSimulatorBTCSignSilentPayment(t *testing.T) {
671714
}
672715
})
673716
}
717+
718+
// Tests that the BitBox displays the output as being of the same account in a self-send.
719+
func TestSimulatorSignBTCTransactionSendSelfSameAccount(t *testing.T) {
720+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
721+
t.Helper()
722+
coin := messages.BTCCoin_BTC
723+
724+
input0Keypath := []uint32{86 + hardenedKeyStart, 0 + hardenedKeyStart, 0 + hardenedKeyStart, 0, 0}
725+
input1Keypath := []uint32{86 + hardenedKeyStart, 0 + hardenedKeyStart, 0 + hardenedKeyStart, 0, 1}
726+
727+
prevTx := &wire.MsgTx{
728+
Version: 2,
729+
TxIn: []*wire.TxIn{
730+
{
731+
PreviousOutPoint: *mustOutpoint("3131313131313131313131313131313131313131313131313131313131313131:0"),
732+
Sequence: 0xFFFFFFFF,
733+
},
734+
},
735+
TxOut: []*wire.TxOut{
736+
{
737+
Value: 100_000_000,
738+
PkScript: func() []byte {
739+
_, script := makeTaprootOutput(t, simulatorPub(t, device, input0Keypath...))
740+
return script
741+
}(),
742+
},
743+
},
744+
LockTime: 0,
745+
}
746+
convertedPrevTx := NewBTCPrevTxFromBtcd(prevTx)
747+
748+
scriptConfigs := []*messages.BTCScriptConfigWithKeypath{
749+
{
750+
ScriptConfig: NewBTCScriptConfigSimple(messages.BTCScriptConfig_P2TR),
751+
Keypath: input0Keypath[:3],
752+
},
753+
}
754+
755+
prevTxHash := prevTx.TxHash()
756+
_, _, err := device.BTCSign(
757+
coin,
758+
scriptConfigs,
759+
nil,
760+
&BTCTx{
761+
Version: 2,
762+
Inputs: []*BTCTxInput{
763+
{
764+
Input: &messages.BTCSignInputRequest{
765+
PrevOutHash: prevTxHash[:],
766+
PrevOutIndex: 0,
767+
PrevOutValue: uint64(prevTx.TxOut[0].Value),
768+
Sequence: 0xFFFFFFFF,
769+
Keypath: input0Keypath,
770+
ScriptConfigIndex: 0,
771+
},
772+
PrevTx: convertedPrevTx,
773+
},
774+
},
775+
Outputs: []*messages.BTCSignOutputRequest{
776+
{
777+
Ours: true,
778+
Value: 70_000_000,
779+
Keypath: input1Keypath,
780+
},
781+
},
782+
Locktime: 0,
783+
},
784+
messages.BTCSignInitRequest_DEFAULT,
785+
)
786+
require.NoError(t, err)
787+
788+
switch {
789+
// Display changed in v9.22.0.
790+
case device.Version().AtLeast(semver.NewSemVer(9, 22, 0)):
791+
require.Contains(t,
792+
stdOut.String(),
793+
"This BitBox (same account): bc1psz0tsdr9sgnukfcx4gtwpp5exyeqdycfqjvm2jw6tvsj3k3eavts20yuag",
794+
)
795+
case device.Version().AtLeast(semver.NewSemVer(9, 20, 0)):
796+
require.Contains(t,
797+
stdOut.String(),
798+
"This BitBox02: bc1psz0tsdr9sgnukfcx4gtwpp5exyeqdycfqjvm2jw6tvsj3k3eavts20yuag",
799+
)
800+
}
801+
// Before simulator v9.20, address confirmation data was not written to stdout.
802+
})
803+
}
804+
805+
// Tests that the BitBox displays the output as being of the same keystore, but different account.
806+
func TestSimulatorSignBTCTransactionSendSelfDifferentAccount(t *testing.T) {
807+
testInitializedSimulators(t, func(t *testing.T, device *Device, stdOut *bytes.Buffer) {
808+
t.Helper()
809+
coin := messages.BTCCoin_BTC
810+
811+
input0Keypath := []uint32{86 + hardenedKeyStart, 0 + hardenedKeyStart, 0 + hardenedKeyStart, 0, 0}
812+
input1Keypath := []uint32{86 + hardenedKeyStart, 0 + hardenedKeyStart, 1 + hardenedKeyStart, 0, 0}
813+
814+
prevTx := &wire.MsgTx{
815+
Version: 2,
816+
TxIn: []*wire.TxIn{
817+
{
818+
PreviousOutPoint: *mustOutpoint("3131313131313131313131313131313131313131313131313131313131313131:0"),
819+
Sequence: 0xFFFFFFFF,
820+
},
821+
},
822+
TxOut: []*wire.TxOut{
823+
{
824+
Value: 100_000_000,
825+
PkScript: func() []byte {
826+
_, script := makeTaprootOutput(t, simulatorPub(t, device, input0Keypath...))
827+
return script
828+
}(),
829+
},
830+
},
831+
LockTime: 0,
832+
}
833+
convertedPrevTx := NewBTCPrevTxFromBtcd(prevTx)
834+
835+
scriptConfigs := []*messages.BTCScriptConfigWithKeypath{
836+
{
837+
ScriptConfig: NewBTCScriptConfigSimple(messages.BTCScriptConfig_P2TR),
838+
Keypath: input0Keypath[:3],
839+
},
840+
}
841+
outputScriptConfigs := []*messages.BTCScriptConfigWithKeypath{
842+
{
843+
ScriptConfig: NewBTCScriptConfigSimple(messages.BTCScriptConfig_P2TR),
844+
Keypath: input1Keypath[:3],
845+
},
846+
}
847+
outputScriptConfigIndex := uint32(0)
848+
849+
prevTxHash := prevTx.TxHash()
850+
_, _, err := device.BTCSign(
851+
coin,
852+
scriptConfigs,
853+
outputScriptConfigs,
854+
&BTCTx{
855+
Version: 2,
856+
Inputs: []*BTCTxInput{
857+
{
858+
Input: &messages.BTCSignInputRequest{
859+
PrevOutHash: prevTxHash[:],
860+
PrevOutIndex: 0,
861+
PrevOutValue: uint64(prevTx.TxOut[0].Value),
862+
Sequence: 0xFFFFFFFF,
863+
Keypath: input0Keypath,
864+
ScriptConfigIndex: 0,
865+
},
866+
PrevTx: convertedPrevTx,
867+
},
868+
},
869+
Outputs: []*messages.BTCSignOutputRequest{
870+
{
871+
Ours: true,
872+
Value: 70_000_000,
873+
Keypath: input1Keypath,
874+
OutputScriptConfigIndex: &outputScriptConfigIndex,
875+
},
876+
},
877+
Locktime: 0,
878+
},
879+
messages.BTCSignInitRequest_DEFAULT,
880+
)
881+
882+
// Introduced in v9.22.0.
883+
if !device.Version().AtLeast(semver.NewSemVer(9, 22, 0)) {
884+
require.EqualError(t, err, UnsupportedError("9.22.0").Error())
885+
return
886+
}
887+
require.NoError(t, err)
888+
require.Contains(t,
889+
stdOut.String(),
890+
"This BitBox (account #2): bc1pzeyhtmk2d5jrjunam30dus0p34095m622dq7trm7r0g8pwac2gvqxh8d47",
891+
)
892+
})
893+
}

0 commit comments

Comments
 (0)