mirror of
https://github.com/muun/recovery.git
synced 2025-11-12 06:50:18 -05:00
831 lines
36 KiB
Go
Executable File
831 lines
36 KiB
Go
Executable File
package libwallet
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcd/txscript"
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/muun/libwallet/addresses"
|
|
"github.com/muun/libwallet/walletdb"
|
|
)
|
|
|
|
const (
|
|
basePath = "m/schema:1'/recovery:1'"
|
|
)
|
|
|
|
type input struct {
|
|
outpoint outpoint
|
|
address MuunAddress
|
|
userSignature []byte
|
|
muunSignature []byte
|
|
submarineSwapV1 inputSubmarineSwapV1
|
|
submarineSwapV2 inputSubmarineSwapV2
|
|
incomingSwap inputIncomingSwap
|
|
}
|
|
|
|
func (i *input) OutPoint() Outpoint {
|
|
return &i.outpoint
|
|
}
|
|
|
|
func (i *input) Address() MuunAddress {
|
|
return i.address
|
|
}
|
|
|
|
func (i *input) UserSignature() []byte {
|
|
return i.userSignature
|
|
}
|
|
|
|
func (i *input) MuunSignature() []byte {
|
|
return i.muunSignature
|
|
}
|
|
|
|
func (i *input) SubmarineSwapV1() InputSubmarineSwapV1 {
|
|
return &i.submarineSwapV1
|
|
}
|
|
|
|
func (i *input) SubmarineSwapV2() InputSubmarineSwapV2 {
|
|
return &i.submarineSwapV2
|
|
}
|
|
|
|
func (i *input) IncomingSwap() InputIncomingSwap {
|
|
return &i.incomingSwap
|
|
}
|
|
|
|
func (i *input) MuunPublicNonce() []byte {
|
|
return nil
|
|
}
|
|
|
|
type outpoint struct {
|
|
txId []byte
|
|
index int
|
|
amount int64
|
|
}
|
|
|
|
func (o *outpoint) TxId() []byte {
|
|
return o.txId
|
|
}
|
|
|
|
func (o *outpoint) Index() int {
|
|
return o.index
|
|
}
|
|
|
|
func (o *outpoint) Amount() int64 {
|
|
return o.amount
|
|
}
|
|
|
|
type inputSubmarineSwapV1 struct {
|
|
refundAddress string
|
|
paymentHash256 []byte
|
|
serverPublicKey []byte
|
|
lockTime int64
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV1) RefundAddress() string {
|
|
return i.refundAddress
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV1) PaymentHash256() []byte {
|
|
return i.paymentHash256
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV1) ServerPublicKey() []byte {
|
|
return i.serverPublicKey
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV1) LockTime() int64 {
|
|
return i.lockTime
|
|
}
|
|
|
|
type inputSubmarineSwapV2 struct {
|
|
paymentHash256 []byte
|
|
serverPublicKey []byte
|
|
userPublicKey []byte
|
|
muunPublicKey []byte
|
|
blocksForExpiration int64
|
|
serverSignature []byte
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV2) PaymentHash256() []byte {
|
|
return i.paymentHash256
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV2) ServerPublicKey() []byte {
|
|
return i.serverPublicKey
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV2) UserPublicKey() []byte {
|
|
return i.userPublicKey
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV2) MuunPublicKey() []byte {
|
|
return i.muunPublicKey
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV2) BlocksForExpiration() int64 {
|
|
return i.blocksForExpiration
|
|
}
|
|
|
|
func (i *inputSubmarineSwapV2) ServerSignature() []byte {
|
|
return i.serverSignature
|
|
}
|
|
|
|
type inputIncomingSwap struct {
|
|
sphinx []byte
|
|
htlcTx []byte
|
|
paymentHash []byte
|
|
swapServerPublicKey string
|
|
expirationHeight int64
|
|
collectInSats int64
|
|
}
|
|
|
|
func (i *inputIncomingSwap) Sphinx() []byte {
|
|
return i.sphinx
|
|
}
|
|
|
|
func (i *inputIncomingSwap) HtlcTx() []byte {
|
|
return i.htlcTx
|
|
}
|
|
|
|
func (i *inputIncomingSwap) PaymentHash256() []byte {
|
|
return i.paymentHash
|
|
}
|
|
|
|
func (i *inputIncomingSwap) SwapServerPublicKey() string {
|
|
return i.swapServerPublicKey
|
|
}
|
|
|
|
func (i *inputIncomingSwap) ExpirationHeight() int64 {
|
|
return i.expirationHeight
|
|
}
|
|
|
|
func (i *inputIncomingSwap) CollectInSats() int64 {
|
|
return i.collectInSats
|
|
}
|
|
|
|
func TestPartiallySignedTransaction_SignV1(t *testing.T) {
|
|
const (
|
|
hexTx = "0100000001706bcabdcdcfd519bdb4534f8ace9f8a3cd614e7b00f074cce0a58913eadfffb0100000000ffffffff022cf46905000000001976a914072b22dfb34153d4e084dce8c6655430d37f12d088aca4de8b00000000001976a914fded0987447ef3273cde87bf8b65a11d1fd9caca88ac00000000"
|
|
hexTxOut = "fbffad3e91580ace4c070fb0e714d63c8a9fce8a4f53b4bd19d5cfcdbdca6b70"
|
|
txIndex = 1
|
|
txAmount = 100000000
|
|
|
|
addressPath = "m/schema:1'/recovery:1'/external:1/1"
|
|
originAddress = "n4fbDDpmfZgyjHsp93C5z7rd68Wq5kS2tj"
|
|
|
|
encodedUserKey = "tprv8eJiUjHpVRyTUM1p4XDRUdRZPJLfud22swAv48my1MxaCZztUNRrWxmN6ycdd9a2xfJwLchq5jW9m2jkNpwruijwvygCv41e6YrsqUvw7hQ"
|
|
)
|
|
|
|
txOut1, _ := hex.DecodeString(hexTxOut)
|
|
|
|
inputs := []Input{
|
|
&input{
|
|
outpoint: outpoint{index: txIndex, amount: txAmount, txId: txOut1},
|
|
address: addresses.New(addresses.V1, addressPath, originAddress),
|
|
},
|
|
}
|
|
|
|
inputList := &InputList{inputs: inputs}
|
|
rawTx, _ := hex.DecodeString(hexTx)
|
|
partial, _ := NewPartiallySignedTransaction(inputList, rawTx, nil)
|
|
|
|
userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest())
|
|
// We dont need to use the muunKey in V1
|
|
signedRawTx, err := partial.Sign(userKey, userKey.PublicKey())
|
|
|
|
if err != nil {
|
|
t.Fatalf("failed to sign tx due to %v", err)
|
|
}
|
|
|
|
signedTx := wire.NewMsgTx(0)
|
|
signedTx.Deserialize(bytes.NewReader(signedRawTx.Bytes))
|
|
|
|
verifyInput(t, signedTx, hexTx, txIndex, 0)
|
|
|
|
}
|
|
func TestPartiallySignedTransaction_SignV2(t *testing.T) {
|
|
|
|
const (
|
|
hexTx = "0100000004f3c15d23060a622bef5e0346ba3410ec118b959be0058c282a1e2045af511b720100000000ffffffffb8ac53a0702e45f7d0164cf6164b48fe66b56af23308e9478cb75e3a2627b74a0100000000ffffffff4e54dc96b07fb29f709c30007fc12abdcde6a20bcad73c8ec6124f34ce096f9b0000000000ffffffff4c11c4284a8e48baa4527fd26e7d0c3dda25ffb3a7f92aa2a248b5a76981d8a40000000000ffffffff01a9cbea0b0000000017a914dfca2abd2bb72cf911940a9d16de126cc1cd60368700000000"
|
|
|
|
txIndex1 = 1
|
|
txAmount1 = 50000000
|
|
hexTxOut1 = "721b51af45201e2a288c05e09b958b11ec1034ba46035eef2b620a06235dc1f3"
|
|
hexMuunSig1 = "3045022100d07028674c49d8dabc536db47f1371c2f61fc578cb2c8797a570e3176f5e91c902206a83db8ad5b63e88c48d0ae4e67646fcf6e33d0177a88996c15b280494885e7b01"
|
|
hexTx1 = "0200000001020678c852c6d943cf0d3a9b5102b1a4e2ebccdb4ca2eaae7731c8f59b81172a000000004847304402204a3958c1bd6abcd7b5ec2291bd43391dcfe757068ff0e340dd8f502cb25435b0022076e865730e49e4d126b94675d276545e35afa84feea2873bb5f923b842d90f4801feffffff0224bf45220000000017a914cb81f4e1ff68249e6f4f17a7995007b5a478705b8780f0fa020000000017a914dfca2abd2bb72cf911940a9d16de126cc1cd60368794020000"
|
|
|
|
txIndex2 = 1
|
|
txAmount2 = 50000000
|
|
hexTxOut2 = "4ab727263a5eb78c47e90833f26ab566fe484b16f64c16d0f7452e70a053acb8"
|
|
hexMuunSig2 = "304402201b0c35179a5fa8e6255115450979a77dbb97d89157e236783df0312a5d7bdb2c022064bae7ad0cdc72e4339421067cc65e0c3d03690a5c2d98c32a6ef67f883558a001"
|
|
hexTx2 = "0200000001ff3f3b16506ef957b9ea80287f276ee415380597a4ede7ae45fff6e18d3e13d8000000004847304402204dbe876d7f0761a72ecc2d0e0e45c1ab32d6bd69d5062068984e26af02c4b27102202f2bd18a17821bdce155b13ea2c379bb78c9157f7f44e2e6a8cef1a154ec68ac01feffffff0224bf45220000000017a914684830d4ef58c54b6b3db6b4a3eb7818d418ae258780f0fa020000000017a914dfca2abd2bb72cf911940a9d16de126cc1cd60368794020000"
|
|
|
|
txIndex3 = 0
|
|
txAmount3 = 50000000
|
|
hexTxOut3 = "9b6f09ce344f12c68e3cd7ca0ba2e6cdbd2ac17f00309c709fb27fb096dc544e"
|
|
hexMuunSig3 = "30440220076b14b1c906089546cb40ce05dab38f0388ca65d0bc5183d3c3f7dcb98be52c022001eea4635d56726d990daa92ac26c52c9030c96dddcc92e5d623546580aaaef401"
|
|
hexTx3 = "02000000019fdde3b7eb40584d103a04dd253ffa0ceb458776db56fbee6489aee0d34402d6000000004847304402206abfb750561acac1be3d6ec3eabc1c88ac7ce11f28f5c8162428ce78dabb4d8e0220753c03bf8b9af9c9bf592f52586d39d8aa10c1111f105fea0ce0cf5c82a4574101feffffff0280f0fa020000000017a914dfca2abd2bb72cf911940a9d16de126cc1cd60368724bf45220000000017a9148d7814264268f1f0f98870f95dc69017bd0cce708794020000"
|
|
|
|
txIndex4 = 0
|
|
txAmount4 = 50000000
|
|
hexTxOut4 = "a4d88169a7b548a2a22af9a7b3ff25da3d0c7d6ed27f52a4ba488e4a28c4114c"
|
|
hexMuunSig4 = "30440220145dcce0bf6cceda98b3a9635bd7611d92085ff3ad27690bcf471a6b39620e6c02205ca0a0bd93550e86468e236b291457a3ff84a3b5dedeb10067cc9d3233b5dafa01"
|
|
hexTx4 = "02000000019d657207178c19bb4fd45de6a5f83caadf86bd7519e1569c8daf078a46e565310000000048473044022033c864f4a6ab42ba29d09bb2dd110e55a3c4118fd0a68cbe5c461926cc64d3e9022029a5b57a2a6e24e6f66f4354b74d7ffc7affa6d43843797faa70c84ec47b7b8501feffffff0280f0fa020000000017a914dfca2abd2bb72cf911940a9d16de126cc1cd60368724bf45220000000017a914b392913e36a7017404c60424da4ebb48a53b5bb18794020000"
|
|
|
|
addressPath = "m/schema:1'/recovery:1'/external:1/0"
|
|
originAddress = "2NDeWrsJEwvxwVnvtWzPjhDC5B2LYkFuX2s"
|
|
|
|
encodedMuunKey = "tpubDBYMnFoxYLdMBZThTk4uARTe4kGPeEYWdKcaEzaUxt1cesetnxtTqmAxVkzDRou51emWytommyLWcF91SdF5KecA6Ja8oHK1FF7d5U2hMxX"
|
|
encodedUserKey = "tprv8dfM4H5fYJirMai5Er3LguicgUAyxmcSQbFub5ens16amX1e1HAFiW4SXnFVw9nu9FedFQqTPGTTjPEmgfvvXMKww3UcRpFbbC4DFjbCcTb"
|
|
basePath = "m/schema:1'/recovery:1'"
|
|
)
|
|
|
|
txOut1, _ := hex.DecodeString(hexTxOut1)
|
|
muunSig1, _ := hex.DecodeString(hexMuunSig1)
|
|
txOut2, _ := hex.DecodeString(hexTxOut2)
|
|
muunSig2, _ := hex.DecodeString(hexMuunSig2)
|
|
txOut3, _ := hex.DecodeString(hexTxOut3)
|
|
muunSig3, _ := hex.DecodeString(hexMuunSig3)
|
|
txOut4, _ := hex.DecodeString(hexTxOut4)
|
|
muunSig4, _ := hex.DecodeString(hexMuunSig4)
|
|
|
|
inputs := []Input{
|
|
&input{
|
|
outpoint: outpoint{index: txIndex1, amount: txAmount1, txId: txOut1},
|
|
address: addresses.New(addresses.V2, addressPath, originAddress),
|
|
muunSignature: muunSig1},
|
|
&input{
|
|
outpoint: outpoint{index: txIndex2, amount: txAmount2, txId: txOut2},
|
|
address: addresses.New(addresses.V2, addressPath, originAddress),
|
|
muunSignature: muunSig2},
|
|
&input{
|
|
outpoint: outpoint{index: txIndex3, amount: txAmount3, txId: txOut3},
|
|
address: addresses.New(addresses.V2, addressPath, originAddress),
|
|
muunSignature: muunSig3},
|
|
&input{
|
|
outpoint: outpoint{index: txIndex4, amount: txAmount4, txId: txOut4},
|
|
address: addresses.New(addresses.V2, addressPath, originAddress),
|
|
muunSignature: muunSig4},
|
|
}
|
|
|
|
inputList := &InputList{inputs: inputs}
|
|
rawTx, _ := hex.DecodeString(hexTx)
|
|
partial, _ := NewPartiallySignedTransaction(inputList, rawTx, nil)
|
|
|
|
muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath, Regtest())
|
|
userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest())
|
|
signedRawTx, err := partial.Sign(userKey, muunKey)
|
|
|
|
if err != nil {
|
|
t.Fatalf("failed to sign tx due to %v", err)
|
|
}
|
|
|
|
signedTx := wire.NewMsgTx(0)
|
|
signedTx.Deserialize(bytes.NewReader(signedRawTx.Bytes))
|
|
|
|
verifyInput(t, signedTx, hexTx1, txIndex1, 0)
|
|
verifyInput(t, signedTx, hexTx2, txIndex2, 0)
|
|
verifyInput(t, signedTx, hexTx3, txIndex3, 0)
|
|
verifyInput(t, signedTx, hexTx4, txIndex4, 0)
|
|
|
|
}
|
|
|
|
func TestPartiallySignedTransaction_SignV3(t *testing.T) {
|
|
const (
|
|
hexTx = "01000000014a4ca718419999e9bfb675dc9f7deff6b65512c11469a23d169038267cd097040100000000ffffffff02916067590000000017a91437a2fceeb0c454b22b427c34eb565d8b1dc953ed8797c400000000000017a9142b0cabe5d058bc3c58f8a656dec2601d117262538700000000"
|
|
|
|
txIndex1 = 1
|
|
txAmount1 = 1500000000
|
|
hexTxOut1 = "0497d07c263890163da26914c11255b6f6ef7d9fdc75b6bfe999994118a74c4a"
|
|
hexMuunSig1 = "3045022100d138caf8d3c19db84363b33e1ad002e1aee7907302ab5110edaf78d980c94e48022019e841da8759f63596fbcd81a3544219573288877206f8f651cae1023c397f0c01"
|
|
hexTx1 = "02000000014f1e7a952c72670bf03a040faa183687ec8c9e0fb7adf606d1ce13395fb663000000000017160014a89e2ded102b2dde96e8bc87219113c6d31a1fe4feffffff02240e5ea9cf00000017a9142773c1a1651ad774f4b867d955ae8b816ac806ad87002f68590000000017a9142b0cabe5d058bc3c58f8a656dec2601d117262538736010000"
|
|
|
|
encodedMuunKey = "tpubDABPYHYrYQHXY2pYFdcsFd41aE2uZmMQZpRRGiKfgz7G7nU7PoSwrzMKeHHnoMjmn9woC87coUanF2T911R8X5HpUtZRJRf56u4r51gTrqD"
|
|
encodedUserKey = "tprv8ezdJAiJTZz4BJo1VysKviVqto1f8CAS3d2M9LWZ5oygiMrtb6NYcPnkWTcdP8b2AuKVVegnWe3Czzo7geDqH2MzXvzDu1SiKucVAG6KFvE"
|
|
|
|
addressPath = "m/schema:1'/recovery:1'/external:1/0"
|
|
originAddress = "2MwArDxm83HCWKvoLKcKAg1Nv6ZG7fWYzMa"
|
|
)
|
|
|
|
txOut1, _ := hex.DecodeString(hexTxOut1)
|
|
muunSig1, _ := hex.DecodeString(hexMuunSig1)
|
|
|
|
inputs := []Input{
|
|
&input{
|
|
outpoint: outpoint{index: txIndex1, amount: txAmount1, txId: txOut1},
|
|
address: addresses.New(addresses.V3, addressPath, originAddress),
|
|
muunSignature: muunSig1},
|
|
}
|
|
|
|
inputList := &InputList{inputs: inputs}
|
|
rawTx, _ := hex.DecodeString(hexTx)
|
|
partial, _ := NewPartiallySignedTransaction(inputList, rawTx, nil)
|
|
|
|
muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath, Regtest())
|
|
userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest())
|
|
signedRawTx, err := partial.Sign(userKey, muunKey)
|
|
|
|
if err != nil {
|
|
t.Fatalf("failed to sign tx due to %v", err)
|
|
}
|
|
|
|
signedTx := wire.NewMsgTx(0)
|
|
signedTx.Deserialize(bytes.NewReader(signedRawTx.Bytes))
|
|
|
|
verifyInput(t, signedTx, hexTx1, txIndex1, 0)
|
|
}
|
|
|
|
func TestPartiallySignedTransaction_SignSubmarineSwapV1(t *testing.T) {
|
|
const (
|
|
hexTx = "01000000021a608c7d6e40586806c33b3b1036fbd305c37e9d38990d912cc02de7e7cec05e0000000000fffffffff18bce10875329410641316bf7c4d984e00780174b6983080e9225dc26e5bd8c0100000000feffffff01705bc0230000000017a91470fcbc29723c85fdbf9fb5189220f279e9be4508878f030000"
|
|
|
|
txIndex1 = 0
|
|
txAmount1 = 599817960
|
|
hexTxOut1 = "5ec0cee7e72dc02c910d99389d7ec305d3fb36103b3bc3066858406e7d8c601a"
|
|
hexTx1 = "0100000006f65ae1c782a5b37795a203a8820719100b1c82f59a4aa1cf3bbcc121442636a50000000023220020f1dcb100a8f4249af53e2ef831e2164545f329a5e8cda589210c033896cd1f12fffffffff21cc482a9359d2762f0a3621eb825e4e728b848588767aecdd8f906833e578e0100000023220020f1dcb100a8f4249af53e2ef831e2164545f329a5e8cda589210c033896cd1f12ffffffff68b507462f19a913b7a6a2a6956cd1c514e66b669d50b3f6228cc21935b78b7f00000000232200203ec9de492dfda91c6d7e84a14f478b1fd6c4b3432aeb4262482133975f94e8f2fffffffff18bce10875329410641316bf7c4d984e00780174b6983080e9225dc26e5bd8c00000000232200209f60ba93792ab212523ad6e6daaefb06d3d0c14ba02ddeaa38582031578bbbd3ffffffff741c42cabd1464b5752e4050acc9d9dfa7ccb296d3847a0e7da6d90effa0d80b0000000023220020d4cf5b8c1ddaa1e2788596655df089cbe10ad33bae149160e07dd76b54e2a1e3ffffffffa609573ae63856433d80793d44d05b077b2c5ef1cc04d820de0d107303ce831b0000000023220020b90f5d2eaf489a24ec6f6d93a47536145fbae13b745fbc7ef9fc5a16d1fa2408ffffffff01e87ec0230000000017a91417c1f13d6ba17a62d6f1f784927c0d45ba22f6fa8700000000"
|
|
txAddressPath1 = "m/schema:1'/recovery:1'/external:1/2"
|
|
txAddress1 = "2MuQqs3e42GpYteWDGEN16TqCQDC8oGCpiV"
|
|
txMuunSigHex1 = "3044022032b35746170883b2f46c2f14019eb95e2e7e4d800248e6a8b372e504dc48674b02202ff47b29abf8f1be8719e757cbd218a4111c214b0c1aa4bdfc7debaf1b46880f01"
|
|
|
|
txIndex2 = 1
|
|
txAmount2 = 18400
|
|
hexTxOut2 = "8cbde526dc25920e0883694b178007e084d9c4f76b3141064129538710ce8bf1"
|
|
hexTx2 = "0100000001c00ee241359fa47d45f4f08b67e37f7a31ebe996da59513dfc6c5af97a3959610100000023220020f1dcb100a8f4249af53e2ef831e2164545f329a5e8cda589210c033896cd1f12ffffffff02a064f5050000000017a914d2bf8b44779443e9a7571ab416c72cdee9e9d06e87e04700000000000017a9140c02072aee07d46ab06edb7d75d538c133ebd8c38700000000"
|
|
txAddressPath2 = "m/schema:1'/recovery:1'/change:0/7"
|
|
txAddress2 = "2MtLiXVbDBQdHKDAKwAL5AnsTo6LoCakjvg"
|
|
txPaymentHashHex2 = "0634be42f7a600c0457ace25f2502e9e473b7d5f0e50172dcce25044c8538936"
|
|
txServerPubKeyHex2 = "035560f6c13e630b4a4b58dac162d4cebd97eb7a96c7ba3636a0bece5c19c2c6dd"
|
|
txLockTime2 = 911
|
|
txRefundAddress2 = "n3yUtyw6xAnYNpfkbuVKPSqnGdbqsLNePr"
|
|
|
|
encodedMuunKey = "tpubDBZaivUL3Hv8r25JDupShPuWVkGcwM7NgbMBwkhQLfWu18iBbyQCbRdyg1wRMjoWdZN7Afg3F25zs4c8E6Q4VJrGqAw51DJeqacTFABV9u8"
|
|
encodedUserKey = "tprv8fFtghPy2BsdB8nrBZcrHSihQDb65yVJa5DfLcFdtjnRc8SQcV4d59hZAzn2auLdEom9KscWv5JAuxUG65gDYiBxwbGarcix7H2Vp8xXPnX"
|
|
)
|
|
|
|
txOut1, _ := hex.DecodeString(hexTxOut1)
|
|
txOut2, _ := hex.DecodeString(hexTxOut2)
|
|
|
|
muunSig1, _ := hex.DecodeString(txMuunSigHex1)
|
|
paymentHash2, _ := hex.DecodeString(txPaymentHashHex2)
|
|
serverPubKey2, _ := hex.DecodeString(txServerPubKeyHex2)
|
|
|
|
inputs := []Input{
|
|
&input{
|
|
outpoint: outpoint{index: txIndex1, amount: txAmount1, txId: txOut1},
|
|
address: addresses.New(addresses.V3, txAddressPath1, txAddress1),
|
|
muunSignature: muunSig1,
|
|
},
|
|
&input{
|
|
outpoint: outpoint{index: txIndex2, amount: txAmount2, txId: txOut2},
|
|
address: addresses.New(addresses.SubmarineSwapV1, txAddressPath2, txAddress2),
|
|
submarineSwapV1: inputSubmarineSwapV1{
|
|
refundAddress: txRefundAddress2,
|
|
paymentHash256: paymentHash2,
|
|
serverPublicKey: serverPubKey2,
|
|
lockTime: txLockTime2,
|
|
},
|
|
},
|
|
}
|
|
|
|
inputList := &InputList{inputs: inputs}
|
|
rawTx, _ := hex.DecodeString(hexTx)
|
|
partial, _ := NewPartiallySignedTransaction(inputList, rawTx, nil)
|
|
|
|
muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath, Regtest())
|
|
userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath, Regtest())
|
|
signedRawTx, err := partial.Sign(userKey, muunKey)
|
|
|
|
if err != nil {
|
|
t.Fatalf("failed to sign tx due to %v", err)
|
|
}
|
|
|
|
signedTx := wire.NewMsgTx(0)
|
|
signedTx.Deserialize(bytes.NewReader(signedRawTx.Bytes))
|
|
|
|
verifyInput(t, signedTx, hexTx1, txIndex1, 0)
|
|
verifyInput(t, signedTx, hexTx2, txIndex2, 1)
|
|
}
|
|
|
|
func verifyInput(t *testing.T, signedTx *wire.MsgTx, hexPrevTx string, prevIndex, index int) {
|
|
t.Helper()
|
|
|
|
// Uncomment the next block if you need to see what the script engine outputs
|
|
txscript.DisableLog()
|
|
// logger := btclog.NewBackend(os.Stderr).Logger("test")
|
|
// logger.SetLevel(btclog.LevelTrace)
|
|
// txscript.UseLogger(logger)
|
|
|
|
prevTx := wire.NewMsgTx(0)
|
|
|
|
rawPrevTx, _ := hex.DecodeString(hexPrevTx)
|
|
prevTx.Deserialize(bytes.NewReader(rawPrevTx))
|
|
|
|
flags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures |
|
|
txscript.ScriptStrictMultiSig | txscript.ScriptDiscourageUpgradableNops |
|
|
txscript.ScriptVerifyStrictEncoding | txscript.ScriptVerifyLowS |
|
|
txscript.ScriptVerifyWitness | txscript.ScriptVerifyCheckLockTimeVerify
|
|
|
|
vm, err := txscript.NewEngine(prevTx.TxOut[prevIndex].PkScript, signedTx, index, flags, nil, nil, prevTx.TxOut[prevIndex].Value)
|
|
if err != nil {
|
|
t.Fatalf("failed to build script engine: %v", err)
|
|
}
|
|
|
|
if err := vm.Execute(); err != nil {
|
|
t.Fatalf("failed to verify script: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestPartiallySignedTransaction_SignSubmarineSwapV2(t *testing.T) {
|
|
const (
|
|
hexTx = "010000000001010a1e9552f252c4f94dae951a3a2789263650d69de286ed4813333ac73179b4790000000023220020fc4ea5a79e0de596005a77df25fdc1d76a5bd2ca022b58260830b45dbf48005fffffffff0100000000000000001976a91476e6856729db9c3885fbd72c47bd225990eee4ad88ac03473044022038395a9846c02cc1b87655ea4679f3df127fa5f781c7db3598ee43acc65adab4022051f0f874a8c16544c4ab492b8a091b630703d742599ea17c61b2bfadb747f30e0147304402207bd5a91f032ed3d69a7999d170c696861f36991f6b54e24da4319eaf512ccac402203d3d14c42103261f605b3a870ab10b03ff8b84537575768067e41853d77d2b240187210310df0c435a58758d53821915501301581be8c18b63d5a0dab281aa7f98bcb6e67c210226048275203811ab30a61759f8271280cb754ede8c38b5c51fc662dec441511eac637c76a914f722e6b3c976eba035578a7b268de980682d60b1876375677cac6867029000b275ad76a9141528942b8aef6f523d8050ad6bab416d6199352288ac6800000000"
|
|
|
|
txIndex2 = 0
|
|
txAmount2 = 1000
|
|
hexTxOut2 = "79b47931c73a331348ed86e29dd650362689273a1a95ae4df9c452f252951e0a"
|
|
hexTx2 = "0100000001b9c3208b3cd1c687d73fec2022ac6ce057c00cf8ae060e5579107a8d99681a7f000000006a473044022042d2e34afb3b66b27641c774b467ce854cfa5d4f9a1eaa462174fa3c688208840220651fdeab3a8134c65431dba040b654d9d21f50343f82bc1870b5280eaff89fc101210209d4e395ce720f13439f4f73b0dac8433f2fa17f094c5fcdaa6965bf96ece088ffffffff02e80300000000000017a914fc7ee7c4ce68ca09559d9e8776f0455039ea18d58718ee052a010000001976a9143447bbd5107cb1572eeb8550f74e5d31a4bf5bd888ac00000000"
|
|
txAddressPath2 = "m"
|
|
txAddress2 = "2NGGJJARaFRcARRMDeSWQ46LwU46Z9oKNCZ"
|
|
txPaymentHashHex2 = "cdb14d5fcf498e8785caff18940bbd713b98b4d425ab0503adb92ab08c5850e3"
|
|
txServerPubKeyHex2 = "0226048275203811ab30a61759f8271280cb754ede8c38b5c51fc662dec441511e"
|
|
txBlockForExpiration2 = 144
|
|
txServerSignatureHex2 = "304402207bd5a91f032ed3d69a7999d170c696861f36991f6b54e24da4319eaf512ccac402203d3d14c42103261f605b3a870ab10b03ff8b84537575768067e41853d77d2b2401"
|
|
|
|
encodedMuunKey = "tpubD6NzVbkrYhZ4Yg872usw1wxNYrpCsUmiG4faYMaogSFwJFX9sz8MrR6GNKg4qUDjb3KUYcC9nrUL7tQYfK441qkFP9pwsw6fb8gTW7vJjXq"
|
|
encodedUserKey = "tprv8ZgxMBicQKsPdu1SiZiQbV4K2af648S6jf8Axu7RkgQborzWpQVRzrSvyoYWb5Rmy8VVyFBDjZobn7ZaK3Ax2hLvF9NxJ6gUWNLwgLxRav7"
|
|
)
|
|
|
|
txOut2, _ := hex.DecodeString(hexTxOut2)
|
|
|
|
paymentHash2, _ := hex.DecodeString(txPaymentHashHex2)
|
|
serverPubKey2, _ := hex.DecodeString(txServerPubKeyHex2)
|
|
serverSignature2, _ := hex.DecodeString(txServerSignatureHex2)
|
|
|
|
muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, "m", Regtest())
|
|
userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, "m", Regtest())
|
|
|
|
inputs := []Input{
|
|
&input{
|
|
outpoint: outpoint{index: txIndex2, amount: txAmount2, txId: txOut2},
|
|
address: addresses.New(addresses.SubmarineSwapV2, txAddressPath2, txAddress2),
|
|
submarineSwapV2: inputSubmarineSwapV2{
|
|
paymentHash256: paymentHash2,
|
|
serverPublicKey: serverPubKey2,
|
|
userPublicKey: userKey.PublicKey().Raw(),
|
|
muunPublicKey: muunKey.Raw(),
|
|
blocksForExpiration: txBlockForExpiration2,
|
|
serverSignature: serverSignature2,
|
|
},
|
|
},
|
|
}
|
|
|
|
inputList := &InputList{inputs: inputs}
|
|
rawTx, _ := hex.DecodeString(hexTx)
|
|
partial, _ := NewPartiallySignedTransaction(inputList, rawTx, nil)
|
|
|
|
signedRawTx, err := partial.Sign(userKey, muunKey)
|
|
|
|
if err != nil {
|
|
t.Fatalf("failed to sign tx due to %v", err)
|
|
}
|
|
|
|
signedTx := wire.NewMsgTx(0)
|
|
signedTx.Deserialize(bytes.NewReader(signedRawTx.Bytes))
|
|
|
|
verifyInput(t, signedTx, hexTx2, txIndex2, 0)
|
|
}
|
|
|
|
func TestPartiallySignedTransaction_SignIncomingSwap(t *testing.T) {
|
|
const (
|
|
hexTx = "0100000001e3d55a5423fd70679839f47ed496d61bd4d0964acfa556172c945041eddf3d400000000000ffffffff02f875000000000000220020f411b28870bf089c41f703dbc1a428d60eb7cce61a9d4fa4a5c28ead872d8551963d000000000000220020eee7f6df991fac39aa2fd8054c83ef045c9569507fe4a224c8320162c028267600000000"
|
|
|
|
txIndex = 0
|
|
txAmount = 46200
|
|
hexTxOut = "403ddfed4150942c1756a5cf4a96d0d41bd696d47ef439986770fd23545ad5e3"
|
|
txAddressPath = "m/schema:1'/recovery:1'/invoices:4/1189547938/512484821/1"
|
|
txAddress = "bcrt1qk3mqxrvcdddyhvyywqhwc0vftfqdqt877gt0pxtzety54z73rxsse9hyt9"
|
|
paymentHashHex = "b0e74c22943fd1e2ee86b14fb6f6636c19649910705913f5bfc33014e0ca0fd4"
|
|
sphinxHex = "00035a24206be286645b5e2f81fe6d35bf26ceb70b15257f19e3b744c0ed855c3d8e60c5a8d7553d0a39dd162a50df5169f18129a737da3427095e1049c356e02bb71d9c70858bbf3936fb555c283d9015f4b85d629a24e84c61dc69d537545e4c0104a87a9ab6277083cf7cb21a56f10ed23e754adf357a638970fbcd38e985f42c44b69f1cfaac8dbf711a5b8edf56383d56ad4cafb297025fad5f9c3e79dad7d1342cabde86ea85950bb80237d95b676939461aed0447b88d0010023d653abf498780f7d8f9a1e5784638c893caefe95e23a85285b636ce2af87613c275e61da65255dba4f4bacde8d6efd1c29a4f8e3efb98a3881e280b8613d45dbe38b7b895621850322be927a6beb6aa183c9a11dbf29da8a3d2f6b0b6b8c7e1c62d4926f3dc1e06ead192daba315fbcd5edd2a7d08bcfa50d1b2cc799e98b3415202e7cd91ff54962e4e1d5716c339718ebea926db6e24aacf35ebc362aafcfde4d6264d56a6edf430ae4ade75cdf9c121c3708211407d5c7ad23e2bc8dfe0d71e588b01d2ada797830315ba616f6c79030481dde1d8aa1a37676aaa9a48aec1dcc535daf2547cff2d43c58acd7e09473c46cada1112e82b0502d057ce6a8a629836ea293be93c5d228169c46d0643378e20429ba09e0a236f8dc56a23e9d38509a72e3bb115dc7c959af913b7d561d17fd3df8d490e2d91c4ae16429a3ecfa45212dbd6ccd80d4ac5956ade21c46b4960c08570e0af69ee39d1c23b194f20bc4d5d5cb5ec0b1e3a376a51700d166dce2b09a6e0c2285af7d36c4d0178a1acad0bfd8d913c44506987df6406ad7f134927c5d46be261cc4025f6310e8cb8284f03ae75a75d4ca43ba1d578b1be69d76503370f95eb98a769eaf1e7c3032907f9ab50c450b7177a804b2e9cb8c5a6fe5bbeb07d0ad176961f817119989f090ad162cae302242651c0c69e7b52c36665be795538afc3aef77a1cd0a36a170d572f56eb79e07ee6544da446798b5e0a0ed92cd205288824335b0444e5eda4347d28be9b2a128d50f983c5b16ea2792eda5d352b609a08a15268e758e024dbde13ae42008c03c608c6bb1971c9eb7a1842129b056b9c0690a88c1aea43f9bc20d8e132575a1eae77ba2fe24ee780f42e6b73b7022049518f1c231fd4fe3e91ca443980e52507ebc97f8fc49036c6e141c0e74603ac02814aa0928381228f7aadd798dbaac3603099e94224dd0b51466d392d276f19b990e8b351b73d3e284fc24f1c1ee0bffad64d9415ae8ab358b01dbc7eedfadb181ab8080d0f9c151c445419ee670e8376a112a631c5ec4092aca077086299e406ab304c7f864da801147b0e09b9f8873c85e952550b62684ca9217d1c0763930b019871787b07cabe0ef8b541c2375bc7ceb4ec1153e6f8a48371f7f80c69dcd37a7d53053fde41f87231abdbed68f195ddc6082b9d0e55207fea2c4d0c8045d44bfe55de2fb71ed75f12c0105a2ea480678b73100a943c45b6d2d5556ece82f02bd12d8785f38ac96bba1167b27b40dbd4d1677cf0b96f9311382cc110f739ffba634fa5163c9e1bd6f0279356aeab301eca2398525ec136d9d3aab4634a1fe14b365c8ad4f98e217cdba327945dfe69f3a3b7f8cd932bd761b2b264a371b104559d0a69c8e7ac053512f3e7fd2cf64278f33f7288958042b3166ff0f05e174378c80ab8d01332e862f17e8cd5c74b3de9acb51e9526d8d3305fa51b447fcb289b26c96ff06e6d50a639514491077c9f70757b74c7e26800688a05274fdcf2697e69455742126dc0df95512e478417db81440a5d2f8c671df00d0bafca53a8ed4bf6c8ea0a4c8af39c7bb1103b828547b669b75f780d9d78ddd811dd1a639576b19805088c33e6e7855cc360827516f4de8f4788bf81feb45d6d31ba5277bca2c86d84f8a"
|
|
htlcTxHex = "020000000001042d54f0cbba265e7f2a0873ce9e03879b706b361d3ee18e8d4a29300c0948bee50000000017160014a411cc351bd7c5572a6ba5ba16e3f3f92106425bfeffffff330565534d05b1d0d4b8a1878f1a5c41d3f571f793c528a44d72af276a259bbd000000001716001443891b3727c96d1e1e91aec69b167123a429ed32feffffff4bb7cba13999b98510769270d161f2a8e0f80f1033c72579a78c105ab2b30ebf00000000171600141c9e61f3951956b00c6f215e75e7fb9a5d93988ffefffffffaa153f428dc6c0aa0be74fa56d6563556b4286d5f9b8a431d5acf0b08f00240000000001716001488ef3cc57c509e843387a7c74e55fdc27fe962f2feffffff0178b4000000000000220020b476030d986b5a4bb084702eec3d895a40d02cfef216f09962cac94a8bd119a102473044022059247039c8e3e95d2eb289e35f81b67e5811d5a757b2117cc9dab1cebf830b2e02204d15406ea075d3d4973344b9bf7c151bb39a7e2876551b8500057dce4591fb870121033d8377beee8caf5fccd958bfacfdd3b5dc1948dfad9fb09768d11e69abb76f3402473044022042e242e0c3adca4f8b3a19cbd8eefd80bf8a43debbe51c5759b2f607b7332bc6022020be1288b8dcddfdc1569c766490e8c0ea668ea1bc122d40b59cbe6589e6938701210243b39e7a2d42937b5aecf14d27b200f7486397d92cbb166ae9f3c11259caf9c602473044022024b16f6042b9a664a46ab0c8cfc3424f8a100309f4cb51e9969a62a257255e2b022053f09e518d2ba73f74d7f3feca98df2b38eb45870325a433457277caf1ce7e6a012103f0386dfb783fc1b55d50aa089326dc008fe2fa963b44d3851bc307bbc419d1c4024730440220346c877b9e983a20fbc52fca2132717e2647bba5489e4127e8032c263252c7d502202cea58c807f60c4b6e10262a2eb59daa8bf637465a4ad67db83c59768088bfb70121020dd5d5044667ebd71f0917a6182435afeb408b4142932c9f5d852b5623ca5d6800000000"
|
|
|
|
preimageHex = "D7EA6B6FE58119AA061CBA3A3C1B556DE966053EE0B8A455A2FA5BA6EAE978FA"
|
|
paymentSecretHex = "E06E5076678201F6B1324421315E16B093D7E24CC6F3D76F5A900D6D5DB6313A"
|
|
shortChanId = uint64(17665301721646554283)
|
|
|
|
encodedMuunKey = "tpubDBZaivUL3Hv8r25JDupShPuWVkGcwM7NgbMBwkhQLfWu18iBbyQCbRdyg1wRMjoWdZN7Afg3F25zs4c8E6Q4VJrGqAw51DJeqacTFABV9u8"
|
|
encodedUserKey = "tprv8deMke4d4jbc5wVYMaDpoqsXYuEPvwLPN43iRRwdZqVJCr9Wc9xh5194mMJeLTkLfQHS5CgkuXbZ9uwK9Eogcx2t7JoscYtrFirGsc3kgCr"
|
|
|
|
muunSigHex = "3045022100c4bef5d32c5ed3530cd258df645dfb0298744dee7820095aca1a188a3b2138c102201669e21db8ee4d2b090cbb18e3e52bce40fc5e07be73c1be4d26c9f13c02e69701"
|
|
)
|
|
|
|
txOut, _ := hex.DecodeString(hexTxOut)
|
|
|
|
paymentHash, _ := hex.DecodeString(paymentHashHex)
|
|
sphinx, _ := hex.DecodeString(sphinxHex)
|
|
htlcTx, _ := hex.DecodeString(htlcTxHex)
|
|
|
|
preimage, _ := hex.DecodeString(preimageHex)
|
|
paymentSecret, _ := hex.DecodeString(paymentSecretHex)
|
|
|
|
muunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, "m/schema:1'/recovery:1'", Regtest())
|
|
userKey, _ := NewHDPrivateKeyFromString(encodedUserKey, "m/schema:1'/recovery:1'", Regtest())
|
|
|
|
muunSig, _ := hex.DecodeString(muunSigHex)
|
|
|
|
inputs := []Input{
|
|
&input{
|
|
outpoint: outpoint{index: txIndex, amount: txAmount, txId: txOut},
|
|
address: addresses.New(addresses.IncomingSwap, txAddressPath, txAddress),
|
|
muunSignature: muunSig,
|
|
incomingSwap: inputIncomingSwap{
|
|
sphinx: sphinx,
|
|
htlcTx: htlcTx,
|
|
paymentHash: paymentHash,
|
|
swapServerPublicKey: "03912b4cfbd725133cbc319b444c1dad96a8bb0fcf840adc28c8e05e84ecbaa89b",
|
|
expirationHeight: 5528,
|
|
collectInSats: 0,
|
|
},
|
|
},
|
|
}
|
|
|
|
inputList := &InputList{inputs: inputs}
|
|
rawTx, _ := hex.DecodeString(hexTx)
|
|
|
|
setup()
|
|
|
|
db, _ := openDB()
|
|
db.CreateInvoice(&walletdb.Invoice{
|
|
Preimage: preimage,
|
|
PaymentHash: paymentHash,
|
|
PaymentSecret: paymentSecret,
|
|
KeyPath: "m/schema:1'/recovery:1'/invoices:4/1189547938/512484821",
|
|
ShortChanId: shortChanId,
|
|
AmountSat: txAmount,
|
|
State: walletdb.InvoiceStateUsed,
|
|
})
|
|
|
|
partial, _ := NewPartiallySignedTransaction(inputList, rawTx, nil)
|
|
|
|
signedRawTx, err := partial.Sign(userKey, muunKey)
|
|
|
|
if err != nil {
|
|
t.Fatalf("failed to sign tx due to %v", err)
|
|
}
|
|
|
|
signedTx := wire.NewMsgTx(0)
|
|
signedTx.Deserialize(bytes.NewReader(signedRawTx.Bytes))
|
|
|
|
verifyInput(t, signedTx, htlcTxHex, txIndex, 0)
|
|
}
|
|
|
|
func TestPartiallySignedTransaction_Verify(t *testing.T) {
|
|
|
|
const (
|
|
hexTx1 = "0100000002a51cc04ab631dee48c989a7cd55c4abc451aa958b09d4579cc9852c52baa57ae0100000000ffffffffdf39591fa749826f87a3d7e5fd5f0468d338c3d81dd3b2c953534b0210f98c560000000000ffffffff02a8d6c20400000000220020452f4ae303ec79acd2bce8f7ddb6469f1060d9146003ea34887e5bbdf021c787000e2707000000002200202ccf0ca2c9b5077ce8345785af26a39277003886fb358877e4083a3fcc5cd66700000000"
|
|
|
|
txIndex1 = 1
|
|
txAmount1 = 100000000
|
|
txIdHex1 = "ae57aa2bc55298cc79459db058a91a45bc4a5cd57c9a988ce4de31b64ac01ca5"
|
|
txAddressPath1 = "m/schema:1'/recovery:1'/external:1/0"
|
|
txAddress1 = "bcrt1q9n8segkfk5rhe6p527z67f4rjfmsqwyxlv6csalypqarlnzu6ens8cm8ye"
|
|
txAddressVersion1 = addresses.V4
|
|
|
|
txIndex2 = 0
|
|
txAmount2 = 100000000
|
|
txIdHex2 = "568cf910024b5353c9b2d31dd8c338d368045ffde5d7a3876f8249a71f5939df"
|
|
txAddressPath2 = "m/schema:1'/recovery:1'/external:1/0"
|
|
txAddress2 = "bcrt1q9n8segkfk5rhe6p527z67f4rjfmsqwyxlv6csalypqarlnzu6ens8cm8ye"
|
|
txAddressVersion2 = addresses.V4
|
|
|
|
changeAddress1 = "bcrt1qg5h54ccra3u6e54uarmamdjxnugxpkg5vqp75dyg0edmmuppc7rsdfcvcp"
|
|
changePath1 = "m/schema:1'/recovery:1'/change:0/1"
|
|
changeVersion1 = addresses.V4
|
|
|
|
hexTx2 = "01000000010ead2fa0d6866d0414aba97fd8f1b242fdc3d4c8e7771e40969402319b6e876b0000000000ffffffff02922988040000000017a914d1ac5d61107d2bef187d1aef5cfd3536f4fd5dbe87d6b2050100000000220020bac6de765432ee16e10ce268341062f8f5a417b15a7f6ee8fe903e6d7470f0f700000000"
|
|
|
|
txIndex3 = 0
|
|
txAmount3 = 93266680
|
|
txIdHex3 = "6b876e9b31029496401e77e7c8d4c3fd42b2f1d87fa9ab14046d86d6a02fad0e"
|
|
txAddressPath3 = "m/schema:1'/recovery:1'/change:0/8"
|
|
txAddress3 = "bcrt1q9yzsghvmmn7wv3esylrvn3c469s4ce4thk7qmxdly4tzk4f8vvjsqv0crh"
|
|
txAddressVersion3 = addresses.V4
|
|
|
|
hexTx4 = "0100000002a51cc04ab631dee48c989a7cd55c4abc451aa958b09d4579cc9852c52baa57ae0100000000ffffffffdf39591fa749826f87a3d7e5fd5f0468d338c3d81dd3b2c953534b0210f98c560000000000ffffffff01000e2707000000002200202ccf0ca2c9b5077ce8345785af26a39277003886fb358877e4083a3fcc5cd66700000000"
|
|
|
|
changeAddress2 = "bcrt1qg5h54ccra3u6e54uarmamdjxnugxpkg5vqp75dyg0edmmuppc7rsdfcvcp"
|
|
changePath2 = "m/schema:1'/recovery:1'/change:0/1"
|
|
changeVersion2 = addresses.V4
|
|
|
|
encodedUserKey = "tpubDAKxNPypXDF3GNCpXFUh6sCdxz7DY9eKMgFxYBgyRSiYWXrBLgdtkPuMbQQzrsYLVyPPSHmNcduLRRd9TSMaYrGLryp8KNkkYBm6eka1Bem"
|
|
encodedMuunKey = "tpubDBZaivUL3Hv8r25JDupShPuWVkGcwM7NgbMBwkhQLfWu18iBbyQCbRdyg1wRMjoWdZN7Afg3F25zs4c8E6Q4VJrGqAw51DJeqacTFABV9u8"
|
|
|
|
basePath = "m/schema:1'/recovery:1'"
|
|
)
|
|
|
|
txId1, _ := hex.DecodeString(txIdHex1)
|
|
txId2, _ := hex.DecodeString(txIdHex2)
|
|
txId3, _ := hex.DecodeString(txIdHex3)
|
|
|
|
userPublicKey, _ := NewHDPublicKeyFromString(
|
|
encodedUserKey,
|
|
basePath,
|
|
Regtest())
|
|
|
|
muunPublicKey, _ := NewHDPublicKeyFromString(
|
|
encodedMuunKey,
|
|
basePath,
|
|
Regtest())
|
|
|
|
type fields struct {
|
|
tx string
|
|
inputs []Input
|
|
}
|
|
type args struct {
|
|
expectations *SigningExpectations
|
|
userPublicKey *HDPublicKey
|
|
muunPublickKey *HDPublicKey
|
|
}
|
|
firstInput := input{
|
|
outpoint: outpoint{index: txIndex1, amount: txAmount1, txId: txId1},
|
|
address: addresses.New(txAddressVersion1, txAddressPath1, txAddress1),
|
|
}
|
|
secondInput := input{
|
|
outpoint: outpoint{index: txIndex2, amount: txAmount2, txId: txId2},
|
|
address: addresses.New(txAddressVersion2, txAddressPath2, txAddress2),
|
|
}
|
|
secondInputGeneratingDust := input{
|
|
outpoint: outpoint{index: txIndex2, amount: 120000000 - txAmount1 + 122200 + 100 /* dust */, txId: txId2},
|
|
address: addresses.New(txAddressVersion2, txAddressPath2, txAddress2),
|
|
}
|
|
thirdInput := input{
|
|
outpoint: outpoint{index: txIndex3, amount: txAmount3, txId: txId3},
|
|
address: addresses.New(txAddressVersion3, txAddressPath3, txAddress3),
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "2 inputs, one change",
|
|
fields: fields{
|
|
tx: hexTx1,
|
|
inputs: []Input{&firstInput, &secondInput},
|
|
},
|
|
args: args{
|
|
expectations: &SigningExpectations{
|
|
destination: "bcrt1q9n8segkfk5rhe6p527z67f4rjfmsqwyxlv6csalypqarlnzu6ens8cm8ye",
|
|
amount: 120000000,
|
|
change: addresses.New(changeVersion1, changePath1, changeAddress1),
|
|
fee: 122200,
|
|
},
|
|
userPublicKey: userPublicKey,
|
|
muunPublickKey: muunPublicKey,
|
|
},
|
|
},
|
|
{
|
|
name: "lied about destination amount",
|
|
fields: fields{
|
|
tx: hexTx1,
|
|
inputs: []Input{&firstInput, &secondInput},
|
|
},
|
|
args: args{
|
|
expectations: &SigningExpectations{
|
|
destination: "bcrt1q9n8segkfk5rhe6p527z67f4rjfmsqwyxlv6csalypqarlnzu6ens8cm8ye",
|
|
amount: 110000000,
|
|
change: addresses.New(changeVersion1, changePath1, changeAddress1),
|
|
fee: 122200,
|
|
},
|
|
userPublicKey: userPublicKey,
|
|
muunPublickKey: muunPublicKey,
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "lied about change",
|
|
fields: fields{
|
|
tx: hexTx1,
|
|
inputs: []Input{&firstInput, &secondInput},
|
|
},
|
|
args: args{
|
|
expectations: &SigningExpectations{
|
|
destination: "bcrt1q9n8segkfk5rhe6p527z67f4rjfmsqwyxlv6csalypqarlnzu6ens8cm8ye",
|
|
amount: 120000000,
|
|
change: addresses.New(changeVersion1, basePath+"/123", changeAddress1),
|
|
fee: 122200,
|
|
},
|
|
userPublicKey: userPublicKey,
|
|
muunPublickKey: muunPublicKey,
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "lied about destination",
|
|
fields: fields{
|
|
tx: hexTx1,
|
|
inputs: []Input{&firstInput, &secondInput},
|
|
},
|
|
args: args{
|
|
expectations: &SigningExpectations{
|
|
destination: "2N2giv9tsN3pV7Rkm89SReRBgdqKNBESVBk",
|
|
amount: 120000000,
|
|
change: addresses.New(changeVersion1, changePath1, changeAddress1),
|
|
fee: 122200,
|
|
},
|
|
userPublicKey: userPublicKey,
|
|
muunPublickKey: muunPublicKey,
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "lied about fee",
|
|
fields: fields{
|
|
tx: hexTx1,
|
|
inputs: []Input{&firstInput, &secondInput},
|
|
},
|
|
args: args{
|
|
expectations: &SigningExpectations{
|
|
destination: "bcrt1q9n8segkfk5rhe6p527z67f4rjfmsqwyxlv6csalypqarlnzu6ens8cm8ye",
|
|
amount: 120000000,
|
|
change: addresses.New(changeVersion1, changePath1, changeAddress1),
|
|
fee: 12200,
|
|
},
|
|
userPublicKey: userPublicKey,
|
|
muunPublickKey: muunPublicKey,
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "wasnt expecting change",
|
|
fields: fields{
|
|
tx: hexTx1,
|
|
inputs: []Input{&firstInput, &secondInput},
|
|
},
|
|
args: args{
|
|
expectations: &SigningExpectations{
|
|
destination: "bcrt1q9n8segkfk5rhe6p527z67f4rjfmsqwyxlv6csalypqarlnzu6ens8cm8ye",
|
|
amount: 120000000,
|
|
change: nil,
|
|
fee: 122200,
|
|
},
|
|
userPublicKey: userPublicKey,
|
|
muunPublickKey: muunPublicKey,
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "lying change",
|
|
fields: fields{
|
|
tx: hexTx2,
|
|
inputs: []Input{&thirdInput},
|
|
},
|
|
args: args{
|
|
expectations: &SigningExpectations{
|
|
destination: "bcrt1qhtrduaj5xthpdcgvuf5rgyrzlr66g9a3tflka687jqlx6ars7rms0flpmy",
|
|
amount: 17150678,
|
|
change: addresses.New(changeVersion2, changePath2, changeAddress2),
|
|
fee: 83600,
|
|
},
|
|
userPublicKey: userPublicKey,
|
|
muunPublickKey: muunPublicKey,
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "inputs generating dust",
|
|
fields: fields{
|
|
tx: hexTx4,
|
|
inputs: []Input{&firstInput, &secondInputGeneratingDust},
|
|
},
|
|
args: args{
|
|
expectations: &SigningExpectations{
|
|
destination: "bcrt1q9n8segkfk5rhe6p527z67f4rjfmsqwyxlv6csalypqarlnzu6ens8cm8ye",
|
|
amount: 120000000,
|
|
change: nil,
|
|
fee: 122200,
|
|
},
|
|
userPublicKey: userPublicKey,
|
|
muunPublickKey: muunPublicKey,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
inputList := &InputList{inputs: tt.fields.inputs}
|
|
rawTx, _ := hex.DecodeString(tt.fields.tx)
|
|
p, err := NewPartiallySignedTransaction(inputList, rawTx, nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
err = p.Verify(tt.args.expectations, tt.args.userPublicKey, tt.args.muunPublickKey)
|
|
t.Logf("test %v returned %v", tt.name, err)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("Verify() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|