Giter Club home page Giter Club logo

mrtnetwork / bitcoin Goto Github PK

View Code? Open in Web Editor NEW
23.0 2.0 6.0 4.06 MB

a comprehensive and versatile Go library for all your Bitcoin transaction needs. offers robust support for various Bitcoin transaction types, including spending transactions, Bitcoin address management, Bitcoin Schnorr signatures, BIP-39 mnemonic phrase generation, hierarchical deterministic (HD) wallet derivation, and Secret Storage Definition

License: BSD 3-Clause "New" or "Revised" License

Go 100.00%
bitcoin bitcoin-transaction bitcoin-wallet p2pk p2pkh p2sh p2sh-p2wsh p2tr p2wpkh schnorr-signatures

bitcoin's People

Contributors

mrtnetwork avatar tic8 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

bitcoin's Issues

taproot address send transaction error:non-mandatory-script-verify-flag (Invalid Schnorr signature)

func main() {
 // Private key of the UTXO owner
 privateKey, _ := keypair.NewECPrivateFromWIF("91qdf1RH6UMZwZTnHUJ3RSiGSZ5EAxvW2FgYFV2HeaLnqZQh4zx")

 // Address we want to spend from
 fromAddr := privateKey.GetPublic().ToTaprootAddress()

 // Create an input
 // Insert transaction ID and index of UTXO
 sigTxin1 := scripts.NewTxInput("21c3bbc77f6193890f9e8b4b4fad765a9e72735a7aac551f0ccb28943b8830b5", 0)

 // Address we want to send funds to
 addr, _ := address.P2PKHAddressFromAddress("n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR")

 // Create an output: Send 3000 to `n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR`
 txout := scripts.NewTxOutput(
  big.NewInt(1000),
  addr.ToScriptPubKey(),
 )

 // Create a transaction
 tx := scripts.NewBtcTransaction(
  []*scripts.TxInput{sigTxin1},
  []*scripts.TxOutput{txout},
  true, // The transaction contains one or more segwit UTXOs
 )

 // Get the transaction digest for signing input at index 0
 // Arguments:
 // - Index 0
 // - The scriptPubkeys that correspond to all the inputs/UTXOs
 // - The amounts that correspond to all the inputs/UTXOs
 // - Ext_flag: Extension mechanism, default is 0; 1 is for script spending (BIP342)
 // - Script: The script that we are spending when ext_flag is 1
 digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(3500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)

 // Sign the transaction
 // Arguments:
 // - Transaction digest related to the index
 // - Signature Hash Type (TAPROOT_SIGHASH_ALL)
 // - Script path (tapleafs)
 // - Tweak: Note that we don't use tapleafs script in this transaction, so the tweak should be set to False
 sig := privateKey.SignTaprootTransaction(digest, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, false)

 // Create a witness signature and set it to the transaction at the current index
 witness := scripts.NewTxWitnessInput(sig)
 tx.Witnesses = append(tx.Witnesses, witness)

 // Transaction ID
 tx.TxId()

 // In this case, the transaction is segwit, and we must use GetVSize for transaction size
 tx.GetVSize()

 // Transaction digest ready for broadcast
 digestHex := tx.Serialize()

 api := provider.SelectApi(provider.MempoolApi, &address.TestnetNetwork)
 trId, err := api.SendRawTransaction(digestHex)
 if err != nil {
  fmt.Println("err:", err)
 }
 fmt.Println("trid:", trId)

}

Using the Spend P2TR UTXO code example in README.md (wif has been changed to my own input hash, etc.), sendrawtransaction RPC error is raised: {"code":-26,"message":"non-mandatory-script-verify-flag (Invalid Schnorr signature) "} Error, is there something I set incorrectly?

Error validating transaction

**

This test example, trading broadcast error, please help me

**

network := address.TestnetNetwork
api := provider.SelectApi(provider.BlockCyperApi, &network)
// i generate random mnemonic for test
// mnemoic, _ := bip39.GenerateMnemonic(256)
mnemonic := "spy often critic spawn produce volcano depart fire theory fog turn retire"

// accsess to private and public keys
masterWallet, _ := hdwallet.FromMnemonic(mnemonic, "")

// wallet with path
// i generate 4 HD wallet for this test and now i have access to private and pulic key of each wallet
sp1, _ := hdwallet.DrivePath(masterWallet, "m/44'/0'/0'/0/0/1")
sp2, _ := hdwallet.DrivePath(masterWallet, "m/44'/0'/0'/0/0/2")
sp3, _ := hdwallet.DrivePath(masterWallet, "m/44'/0'/0'/0/0/3")
sp4, _ := hdwallet.DrivePath(masterWallet, "m/44'/0'/0'/0/0/4")

// access to private key `ECPrivate`
private1, _ := sp1.GetPrivate()
private2, _ := sp2.GetPrivate()
private3, _ := sp3.GetPrivate()
private4, _ := sp4.GetPrivate()
// access to public key `ECPublic`
public1 := sp1.GetPublic()
public2 := sp2.GetPublic()
public3 := sp3.GetPublic()
public4 := sp4.GetPublic()

signer1, _ := provider.CreateMultiSignaturSigner(
	// public key of signer
	public1.ToHex(),
	// siger weight
	2,
)
signer2, _ := provider.CreateMultiSignaturSigner(
	public2.ToHex(),
	2,
)
signer3, _ := provider.CreateMultiSignaturSigner(
	public3.ToHex(),
	1,
)
signer4, _ := provider.CreateMultiSignaturSigner(
	public4.ToHex(),
	1,
)

/*
	In general, this address requires 5 signatures to spend:
	2 signatures from signer1
	2 signatures from signer2
	and 1 signature from either signer 3 or signer 4.
	And the address script is as follows

	["OP_5", public1 ,public1 ,public2 ,public2 ,public3 ,public4, "OP_6", "OP_CHECKMULTISIG"]

	And the unlock script will be like this

	["", signer1Signataure, signer1Signataure, signer2Signatur, signer2Signatur, (signer3Signatur or signer4Signatur), ScriptInHex ]

*/
multiSigBuilder, err := provider.CreateMultiSignatureAddress(
	5, provider.MultiSignaturAddressSigners{
		signer1,
		signer2, signer3, signer4,
	}, address.P2WSHInP2SH, // P2SH(P2WSH)
)
if err != nil {
	fmt.Println(err)
	return
}

/*
	In general, this address requires 5 signatures to spend:
	2 signatures from signer1
	2 signatures from signer2
	and 1 signature from either signer 3 or signer 4.
	And the address script is as follows

	["OP_5", public1 ,public1 ,public2 ,public2 ,public3 ,public4, "OP_6", "OP_CHECKMULTISIG"]

	And the unlock script will be like this

	["", signer1Signataure, signer1Signataure, signer2Signatur, signer2Signatur, (signer3Signatur or signer4Signatur), ScriptInHex ]
*/
multiSigBuilder2, err2 := provider.CreateMultiSignatureAddress(
	5, provider.MultiSignaturAddressSigners{
		signer1,
		signer2, signer3, signer4,
	}, address.P2WSH, // P2WSH
)
if err2 != nil {
	fmt.Println(err2)
	return
}
// P2SH(P2WSH) 5-6 multi-sig ADDRESS
// 2MxVXBKFwvkWFeN4nij3n8s2GMeBeqF6cL4
multiSigAddress := multiSigBuilder.Address

// P2SH(P2WPKH) 5-6 multi-sig ADDRESS
// tb1q4aw8qjc4eys27y8hnslzqexkgs920ewx8ssuxhwq0sc28vly0w0sv3mvu9
multiSigAddress2 := multiSigBuilder2.Address

// P2TR ADDRESS
// tb1pyhmqwlcrws4dxcgalt4mrffgnys879vs59xf6sve4hazyvmhecxq3e6sc0
// equals to exampleAddr1 := address.P2TRAddressFromAddress("tb1pyhmqwlcrws4dxcgalt4mrffgnys879vs59xf6sve4hazyvmhecxq3e6sc0")
exampleAddr1 := public2.ToTaprootAddress()

// P2SH(P2PK) ADDRESS
// 2MugsNcgzLJ1HosnZyC2CfZVmgbMPK1XubR
// equals to exampleAddr2 := address.P2SHAddressFromAddress("2MugsNcgzLJ1HosnZyC2CfZVmgbMPK1XubR", address.P2PKInP2SH)
exampleAddr2 := public4.ToP2PKInP2SH()

// P2WSH ADDRESS
// tb1qf4qwtr5kp5q87dtp3ul3402vkzssxfv7f4aettjq2hcfhnt92dmq5xzs6n
// equals to exampleAddr3 := address.P2WSHAddresssFromAddress("tb1qf4qwtr5kp5q87dtp3ul3402vkzssxfv7f4aettjq2hcfhnt92dmq5xzs6n")
// created with 1-1 MultiSig script: ["OP_1", publicHex(Hex of compressed public key) , "OP_1", "OP_CHECKMULTISIG"]
exampleAddr3 := public3.ToP2WSHAddress()

// now we chose some address for spending from multiple address
// i use some different address type for this
spenders := []provider.UtxoOwnerDetails{
	{Address: multiSigAddress, MultiSigAddress: multiSigBuilder2},
	{Address: multiSigAddress2, MultiSigAddress: multiSigBuilder2},
	{PublicKey: public2.ToHex(), Address: exampleAddr1},
}

// now we need to read spenders account UTXOS
utxos := provider.UtxoWithOwnerList{}

// i add some method for provider to read utxos from mempol or blockCypher
// looping address to read Utxos
for _, spender := range spenders {
	// read ech address utxo from mempol
	spenderUtxos, err := api.GetAccountUtxo(spender)
	// oh something bad happen when reading Utxos
	if err != nil {
		fmt.Println("something bad happen when reading Utxos: ", err)
		return
	}
	// oh this address does not have any satoshi for spending
	if !spenderUtxos.CanSpending() {
		fmt.Println("address does not have any satoshi for spending: ", spender.Address.Show(network))
		continue
	}

	// we append address utxos to utxos list
	utxos = append(utxos, spenderUtxos...)

}
// Well, now we calculate how much we can spend
sumOfUtxo := utxos.SumOfUtxosValue()

hasSatoshi := sumOfUtxo.Cmp(big.NewInt(0)) != 0

if !hasSatoshi {
	// Are you kidding? We don't have btc to spend
	fmt.Println("Are you kidding? We don't have btc to spend")
	return
}

fmt.Println("sum of Utxos: ", *sumOfUtxo)
// 656,928 sum of all utxos

// We consider 50,000 satoshi for the cost
// in next example i show you how to calculate fee
FEE := big.NewInt(3000)

// now we have 606,920 for spending let do it
// we create 5 different output with  different address type
// We consider the spendable amount for 5 outputs and divide by 5, each output 121,384

output3 := provider.BitcoinOutputDetails{
	Address: exampleAddr3,
	Value:   big.NewInt(1000),
}
output4 := provider.BitcoinOutputDetails{
	Address: exampleAddr2,
	Value:   big.NewInt(1000),
}
output5 := provider.BitcoinOutputDetails{
	Address: exampleAddr1,
	Value:   big.NewInt(1000),
}
output6 := provider.BitcoinOutputDetails{
	Address: multiSigAddress,
	Value:   big.NewInt(1000),
}
output7 := provider.BitcoinOutputDetails{
	Address: multiSigAddress2,
	Value:   big.NewInt(1000),
}

// Well, now it is clear to whom we are going to pay the amount
// Now let's create the transaction
transactionBuilder := provider.NewBitcoinTransactionBuilder(
	// Now, we provide the UTXOs we want to spend.
	utxos,
	// We select transaction outputs
	[]provider.BitcoinOutputDetails{output3, output4, output5, output6, output7},
	/*
		Transaction fee
		Ensure that you have accurately calculated the amounts.
		If the sum of the outputs, including the transaction fee,
		does not match the total amount of UTXOs,
		it will result in an error. Please double-check your calculations.
	*/
	FEE,
	// network (address.BitcoinNetwork ,ddress.TestnetNetwork)
	&network,

	// If you like the note write something else and leave it blank
	// I will put my GitHub address here
	"https://github.com/MohsenHaydari",
	/*
		RBF, or Replace-By-Fee, is a feature in Bitcoin that allows you to increase the fee of an unconfirmed
		transaction that you've broadcasted to the network.
		This feature is useful when you want to speed up a
		transaction that is taking longer than expected to get confirmed due to low transaction fees.
	*/
	true,
)

// now we use BuildTransaction to complete them
// I considered a method parameter for this, to sign the transaction

// utxo Utxo infos with owner details
// trDigest transaction digest of current UTXO (must be sign with correct privateKey)

// tweak: cheack is script path spending or tweaking the script.
// If tweak is set to false, it implies that you are not using the script path spending feature of Taproot,
// and you intend to sign the transaction using the actual script conditions.

// sighash
// Each input in a Bitcoin transaction can include a "sighash type."
// This type is a flag that determines which parts of the transaction are covered by the digital signature.
// Common sighash types include SIGHASH_ALL, SIGHASH_SINGLE, SIGHASH_ANYONECANPAY, etc.
// This TransactionBuilder only works with SIGHASH_ALL and TAPROOT_SIGHASH_ALL for taproot input
// If you want to use another sighash, you should create another TransactionBuilder
transaction, err := transactionBuilder.BuildTransaction(func(trDigest []byte, utxo provider.UtxoWithOwner, multiSigPublicKey string) (string, error) {
	var key keypair.ECPrivate
	currentPublicKey := utxo.OwnerDetails.PublicKey
	if utxo.IsMultiSig() {
		currentPublicKey = multiSigPublicKey
	}
	// ok we have the public key of the current UTXO and we use some conditions to find private  key and sign transaction
	switch currentPublicKey {
	case public3.ToHex():
		{
			key = *private3
		}
	case public2.ToHex():
		{
			key = *private2
		}

	case public1.ToHex():
		{
			key = *private1
		}
	case public4.ToHex():
		{
			key = *private4
		}
	default:
		{
			return "", errors.New("cannot find private key")
		}
	}
	// Ok, now we have the private key, we need to check which method to use for signing
	// We check whether the UTX corresponds to the P2TR address or not.
	if utxo.Utxo.IsP2tr() {
		// yes is p2tr utxo and now we use SignTaprootTransaction(Schnorr sign)
		return key.SignTaprootTransaction(
			trDigest, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true,
		), nil
	}
	// is seqwit(v0) or lagacy address we use  SingInput (ECDSA)
	return key.SingInput(trDigest, constant.SIGHASH_ALL), nil

})

if err != nil {
	fmt.Println("oh we have some error when build and sign transaction ", err)
	return
}

// ok everything is fine and we need a transaction output for broadcasting
// We use the Serialize method to receive the transaction output
digest := transaction.Serialize()

// we check if transaction is segwit or not
// When one of the input UTXO addresses is SegWit, the transaction is considered SegWit.
isSegwitTr := transactionBuilder.HasSegwit()

// transaction id
transactionId := transaction.TxId()
fmt.Println("transaction ID: ", transactionId)

// transaction size
var transactionSize int

if isSegwitTr {
	transactionSize = transaction.GetVSize()
} else {
	transactionSize = transaction.GetSize()
}
fmt.Println("transaction size: ", transactionSize)

// now we send transaction to network
trId, err := api.SendRawTransaction(digest)

if err != nil {
	fmt.Println("something bad happen when sending transaction: ", err)
	return
}
// Yes, we did :)  72b7244693960879bb07f9f96e87790a8b57bb2e91c8dfd79e6f9b8ee520adff
// Now we check Mempol for what happened https://mempool.space/testnet/tx/72b7244693960879bb07f9f96e87790a8b57bb2e91c8dfd79e6f9b8ee520adff
fmt.Println("Transaction ID: ", trId)

An error occurs when I enter multiple input signatures

How do I sign when I enter multiple input signatures?
I made the following attempts:

  1. When I tried to adjust the number of signatures, an error {"code":-26,"message":" non-mandatory-script-verification-flag (Invalid Schnorr signature)"} was reported,
  2. If I only sign once, {"code":-22,"message":"TX decode failed. Make sure the tx has at least one input."} This error is reported.
  3. I adjusted the sighash GetTransactionTaprootDigest method the value of the parameter, SignTaprootTransaction sighash parameters value, or will be signed at the wrong mistake
// Private key of the UTXO owner
	privateKey, _ := keypair.NewECPrivateFromWIF("91qdf1RH6UMZwZTnHUJ3RSiGSZ5EAxvW2FgYFV2HeaLnqZQh4zx")
	// privateKey, _ := keypair.NewECPrivateFromWIF("cUUUyKDSNuDFtAt8deeSHxjHY5p7M9mvBfp32EFxz62H91WFiX9J")

	// Address we want to spend from
	fromAddr := privateKey.GetPublic().ToTaprootAddress()

	// Create an input
	// Insert transaction ID and index of UTXO
	sigTxin1 := scripts.NewTxInput("0924c8ad1b635f7edfb77321f43ba868ae4d71b9976d639fa6a582b4a7bc4714", 0) //500
	sigTxin2 := scripts.NewTxInput("ab03d8f71103ffe1e346ca65635cdad84dcd658e58c3b3ddd529f777c57ec848", 1) //1000

	// Address we want to send funds to
	// addr, _ := btcAddress.P2PKHAddressFromAddress("n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR")
	addr, _ := btcAddress.P2TRAddressFromAddress("tb1pnztcay5kzpyxcfhfmpth4f32re964zupd3k2f8g53rmcnp9kyz9qjukvm2")

	// Create an output: Send 3000 to `n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR`
	txout := scripts.NewTxOutput(
		big.NewInt(500),
		addr.ToScriptPubKey(),
	)

	changeOut := scripts.NewTxOutput(
		big.NewInt(100),
		fromAddr.ToScriptPubKey(),
	)

	// Create a transaction
	tx := scripts.NewBtcTransaction(
		[]*scripts.TxInput{sigTxin1, sigTxin2},
		[]*scripts.TxOutput{txout, changeOut},
		// []*scripts.TxOutput{txout},
		true, // The transaction contains one or more segwit UTXOs
	)

	// Get the transaction digest for signing input at index 0
	// Arguments:
	// - Index 0
	// - The scriptPubkeys that correspond to all the inputs/UTXOs
	// - The amounts that correspond to all the inputs/UTXOs
	// - Ext_flag: Extension mechanism, default is 0; 1 is for script spending (BIP342)
	// - Script: The script that we are spending when ext_flag is 1
	digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)
	digest2 := tx.GetTransactionTaprootDigest(1, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)
	// digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(3000)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)

	// Sign the transaction
	// Arguments:
	// - Transaction digest related to the index
	// - Signature Hash Type (TAPROOT_SIGHASH_ALL)
	// - Script path (tapleafs)
	// - Tweak: Note that we don't use tapleafs script in this transaction, so the tweak should be set to False
	sig := privateKey.SignTaprootTransaction(digest, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true)
	sig2 := privateKey.SignTaprootTransaction(digest2, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true)
	// sig := privateKey.SignTaprootTransaction(digest, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true) // set to tue

	// Create a witness signature and set it to the transaction at the current index
	witness := scripts.NewTxWitnessInput(sig)
	// witnessOut := scripts.NewTxWitness(sig)
	tx.Witnesses = append(tx.Witnesses, witness)

	witness2 := scripts.NewTxWitnessInput(sig2)
	tx.Witnesses = append(tx.Witnesses, witness2)

	// Transaction ID
	tx.TxId()

	// In this case, the transaction is segwit, and we must use GetVSize for transaction size
	tx.GetVSize()

	// Transaction digest ready for broadcast
	digestHex := tx.Serialize()

	api := provider.SelectApi(provider.MempoolApi, &address.TestnetNetwork)
	trId, err := api.SendRawTransaction(digestHex)
	if err != nil {
		fmt.Println("err:", err)
	}
	fmt.Println("trid:", trId)

load transaction from a rawTrx,I found some txInputs with large txIndex

first, I build a trx with newBtcTransaction,in which the txinput is like : utxo id: 326a778ebde5c6926f0507bdc9ebc84962588efc094c734f7f58e5d7b633fb0c, txIndex is 2, utxo amount 11971

second, I have this trx serilized and get a string

third, I call btcTransactionFromRaw, but I found that txIndex is 2<<24, maybe because my machine is the one need to call reversedByte

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.