Skip to content

Commit

Permalink
V2.1.0
Browse files Browse the repository at this point in the history
fix issue #5
  • Loading branch information
mrtnetwork committed Apr 30, 2024
1 parent 4f24072 commit e37a7a8
Show file tree
Hide file tree
Showing 17 changed files with 418 additions and 282 deletions.
11 changes: 8 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
## 2.1.0

* fix issue [#5](https://github.com/mrtnetwork/bitcoin/issues/5)

## 2.0.0
- Updated golang.org/x/crypto to the latest version v0.18.0
- Resolved issue with Multisignature address

* Updated golang.org/x/crypto to the latest version v0.18.0
* Resolved issue with Multisignature address

## 1.0.0

* Release.
* Release.
421 changes: 226 additions & 195 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ module github.com/mrtnetwork/bitcoin

go 1.21

require golang.org/x/crypto v0.18.0
require golang.org/x/crypto v0.22.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
4 changes: 2 additions & 2 deletions provider/transction_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (builder *BitcoinTransactionBuilder) HasTaproot() bool {
// It is used to make the appropriate scriptSig
func buildInputScriptPubKeys(utxo UtxoWithOwner, isTaproot bool) (*scripts.Script, error) {
if utxo.IsMultiSig() {
script, e := scripts.ScriptFromRaw(utxo.OwnerDetails.MultiSigAddress.ScriptDetails, true)
script, e := scripts.ScriptFromRaw(formating.HexToBytes(utxo.OwnerDetails.MultiSigAddress.ScriptDetails), true)
if e != nil {
return nil, e
}
Expand Down Expand Up @@ -205,7 +205,7 @@ func buildP2shSegwitRedeemScriptSig(utx UtxoWithOwner) ([]string, error) {
if utx.IsMultiSig() {
switch utx.OwnerDetails.MultiSigAddress.Address.GetType() {
case address.P2WSHInP2SH:
script, e := scripts.ScriptFromRaw(utx.OwnerDetails.MultiSigAddress.ScriptDetails, true)
script, e := scripts.ScriptFromRaw(formating.HexToBytes(utx.OwnerDetails.MultiSigAddress.ScriptDetails), true)
if e != nil {
return nil, e
}
Expand Down
36 changes: 16 additions & 20 deletions scripts/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,46 +52,41 @@ func (s *Script) ToP2shScriptPubKey() *Script {
}

// Imports a Script commands list from raw hexadecimal data
func ScriptFromRaw(hexData string, hasSegwit bool) (*Script, error) {
func ScriptFromRaw(scriptBytes []byte, hasSegwit bool) (*Script, error) {
var commands []interface{}
index := 0
scriptraw, err := formating.HexToBytesCatch(hexData)
if err != nil {
return nil, fmt.Errorf("invalid script bytes")
}

for index < len(scriptraw) {
b := int(scriptraw[index])
for index < len(scriptBytes) {
b := int(scriptBytes[index])
if constant.CODE_OPS[b] != "" {
commands = append(commands, constant.CODE_OPS[b])
index++
} else if !hasSegwit && b == 0x4c {
bytesToRead := int(scriptraw[index+1])
bytesToRead := int(scriptBytes[index+1])
index++
data := scriptraw[index : index+bytesToRead]
data := scriptBytes[index : index+bytesToRead]
commands = append(commands, hex.EncodeToString(data))
index += bytesToRead
} else if !hasSegwit && b == 0x4d {
bytesToRead := int(binary.LittleEndian.Uint16(scriptraw[index+1 : index+3]))
bytesToRead := int(binary.LittleEndian.Uint16(scriptBytes[index+1 : index+3]))
index += 3
data := scriptraw[index : index+bytesToRead]
data := scriptBytes[index : index+bytesToRead]
commands = append(commands, hex.EncodeToString(data))
index += bytesToRead
} else if !hasSegwit && b == 0x4e {
bytesToRead := int(binary.LittleEndian.Uint32(scriptraw[index+1 : index+5]))
bytesToRead := int(binary.LittleEndian.Uint32(scriptBytes[index+1 : index+5]))
index += 5
data := scriptraw[index : index+bytesToRead]
data := scriptBytes[index : index+bytesToRead]
commands = append(commands, hex.EncodeToString(data))
index += bytesToRead
} else {
vi, size := formating.ViToInt(scriptraw[index:])
vi, size := formating.ViToInt(scriptBytes[index:])
dataSize := vi
// size := size
lastIndex := index + size + dataSize
if lastIndex > len(scriptraw) {
lastIndex = len(scriptraw)
if lastIndex > len(scriptBytes) {
lastIndex = len(scriptBytes)
}
commands = append(commands, hex.EncodeToString(scriptraw[index+size:lastIndex]))
commands = append(commands, hex.EncodeToString(scriptBytes[index+size:lastIndex]))
index += dataSize + size
}
}
Expand All @@ -100,8 +95,9 @@ func ScriptFromRaw(hexData string, hasSegwit bool) (*Script, error) {

// GetScriptType determines the script type based on the provided hash and whether it has
// SegWit data. It returns the identified ScriptType.
func GetScriptType(hash string, hasSegwit bool) (ScriptType, error) {
s, err := ScriptFromRaw(hash, hasSegwit)
func GetScriptType(scriptBytes []byte, hasSegwit bool) (ScriptType, error) {

s, err := ScriptFromRaw(scriptBytes, hasSegwit)
if err != nil {
return -1, err
}
Expand Down
23 changes: 12 additions & 11 deletions scripts/transaction.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package scripts

import (
"math/big"

"github.com/mrtnetwork/bitcoin/constant"
"github.com/mrtnetwork/bitcoin/digest"
"github.com/mrtnetwork/bitcoin/formating"
"math/big"
)

// Define BtcTransaction struct
Expand Down Expand Up @@ -95,37 +96,37 @@ func (tx *BtcTransaction) Copy() *BtcTransaction {
}
}
func BtcTransactionFromRaw(raw string) (*BtcTransaction, error) {
rawtx := formating.HexToBytes(raw)
txBytes := formating.HexToBytes(raw)
cursor := 4
var flag []byte
hasSegwit := false

if rawtx[4] == 0 {
flag = rawtx[5:6]
if txBytes[4] == 0 {
flag = txBytes[5:6]
if flag[0] == 1 {
hasSegwit = true
}
cursor += 2
}

vi, viCursor := formating.ViToInt(rawtx[cursor:])
vi, viCursor := formating.ViToInt(txBytes[cursor:])
cursor += viCursor

inputs := make([]*TxInput, vi)
for index := 0; index < len(inputs); index++ {
inp, inpCursor, err := TxInputFromRaw(raw, cursor, hasSegwit)
inp, inpCursor, err := TxInputFromRaw(txBytes, cursor, hasSegwit)
if err != nil {
return nil, err
}
inputs[index] = inp
cursor = inpCursor
}
viOut, viOutCursor := formating.ViToInt(rawtx[cursor:])
viOut, viOutCursor := formating.ViToInt(txBytes[cursor:])
cursor += viOutCursor

outputs := make([]*TxOutput, viOut)
for index := 0; index < len(outputs); index++ {
out, outCursor, err := TxOutputFromRaw(raw, cursor, hasSegwit)
out, outCursor, err := TxOutputFromRaw(txBytes, cursor, hasSegwit)
if err != nil {
return nil, err
}
Expand All @@ -135,14 +136,14 @@ func BtcTransactionFromRaw(raw string) (*BtcTransaction, error) {
witnesses := make([]TxWitnessInput, len(inputs))
if hasSegwit {
for n := 0; n < len(inputs); n++ {
wVi, wViCursor := formating.ViToInt(rawtx[cursor:])
wVi, wViCursor := formating.ViToInt(txBytes[cursor:])
cursor += wViCursor
witnessesTmp := make([]string, wVi)
for m := 0; m < len(witnessesTmp); m++ {
var witness []byte
wtVi, wtViCursor := formating.ViToInt(rawtx[cursor:])
wtVi, wtViCursor := formating.ViToInt(txBytes[cursor:])
if wtVi != 0 {
witness = rawtx[cursor+wtViCursor : cursor+wtViCursor+wtVi]
witness = txBytes[cursor+wtViCursor : cursor+wtViCursor+wtVi]
}
cursor += wtViCursor + wtVi
witnessesTmp[m] = formating.BytesToHex(witness)
Expand Down
27 changes: 12 additions & 15 deletions scripts/tx_input.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/binary"
"encoding/hex"
"fmt"

"github.com/mrtnetwork/bitcoin/constant"
"github.com/mrtnetwork/bitcoin/formating"
)
Expand Down Expand Up @@ -81,45 +82,41 @@ func (ti *TxInput) ToBytes() []byte {
}

// FromRaw parses a raw transaction input string into a TxInput
func TxInputFromRaw(raw string, cursor int, hasSegwit bool) (*TxInput, int, error) {
txInputRaw, err := formating.HexToBytesCatch(raw)
if err != nil {
return nil, cursor, err
}
func TxInputFromRaw(inputBytes []byte, cursor int, hasSegwit bool) (*TxInput, int, error) {

if cursor+32 >= len(txInputRaw) {
if cursor+32 >= len(inputBytes) {
return nil, cursor, fmt.Errorf("input transaction hash not found. Probably malformed raw transaction")
}

inpHash := make([]byte, 32)
copy(inpHash, formating.ReverseBytes(txInputRaw[cursor:cursor+32]))
copy(inpHash, formating.ReverseBytes(inputBytes[cursor:cursor+32]))
cursor += 32

if cursor+4 >= len(txInputRaw) {
if cursor+4 >= len(inputBytes) {
return nil, cursor, fmt.Errorf("output number not found. Probably malformed raw transaction")
}

outputN := binary.LittleEndian.Uint32(formating.ReverseBytes(txInputRaw[cursor : cursor+4]))
outputN := binary.LittleEndian.Uint32(inputBytes[cursor : cursor+4])
cursor += 4

vi, viSize := formating.ViToInt(txInputRaw[cursor:])
vi, viSize := formating.ViToInt(inputBytes[cursor:])
cursor += viSize

if cursor+vi > len(txInputRaw) {
if cursor+vi > len(inputBytes) {
return nil, cursor, fmt.Errorf("unlocking script length exceeds available data. Probably malformed raw transaction")
}

unlockingScript := txInputRaw[cursor : cursor+vi]
unlockingScript := inputBytes[cursor : cursor+vi]
cursor += vi

if cursor+4 > len(txInputRaw) {
if cursor+4 > len(inputBytes) {
return nil, cursor, fmt.Errorf("Sequence number not found. Probably malformed raw transaction")
}

sequenceNumberData := txInputRaw[cursor : cursor+4]
sequenceNumberData := inputBytes[cursor : cursor+4]
cursor += 4

script, err := ScriptFromRaw(formating.BytesToHex(unlockingScript), hasSegwit)
script, err := ScriptFromRaw(unlockingScript, hasSegwit)
if err != nil {
return nil, cursor, err
}
Expand Down
15 changes: 8 additions & 7 deletions scripts/tx_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package scripts

import (
"encoding/binary"
"github.com/mrtnetwork/bitcoin/formating"
"math/big"

"github.com/mrtnetwork/bitcoin/formating"
)

type TxOutput struct {
Expand Down Expand Up @@ -42,19 +43,19 @@ func (txOutput *TxOutput) ToBytes() []byte {
// raw The hexadecimal raw string of the Transaction
// The cursor of which the algorithm will start to read the data
// hasSegwit Is the Tx Output segwit or not
func TxOutputFromRaw(raw string, cursor int, hasSegwit bool) (*TxOutput, int, error) {
rawBytes := formating.HexToBytes(raw)
func TxOutputFromRaw(outputBytes []byte, cursor int, hasSegwit bool) (*TxOutput, int, error) {

// Parse TxOutput from raw bytes
value := int64(binary.LittleEndian.Uint64(rawBytes[cursor : cursor+8]))
value := int64(binary.LittleEndian.Uint64(outputBytes[cursor : cursor+8]))
cursor += 8

vi, viSize := formating.ViToInt(rawBytes[cursor:])
vi, viSize := formating.ViToInt(outputBytes[cursor:])
cursor += viSize

lockScript := rawBytes[cursor : cursor+vi]
lockScript := outputBytes[cursor : cursor+vi]
cursor += vi

scriptPubKey, err := ScriptFromRaw(formating.BytesToHex(lockScript), hasSegwit)
scriptPubKey, err := ScriptFromRaw(lockScript, hasSegwit)
if err != nil {
return nil, cursor, err
}
Expand Down
9 changes: 3 additions & 6 deletions test/bip_39_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package test

import (
"fmt"
"github.com/mrtnetwork/bitcoin/bip39"
"github.com/mrtnetwork/bitcoin/formating"
"testing"

"github.com/mrtnetwork/bitcoin/bip39"
)

func TestBip39(t *testing.T) {
Expand All @@ -26,13 +25,11 @@ func TestBip39(t *testing.T) {

// Select the desired number of words. 12(Words12), 15(Words15), 18(Words18), 21(Words21) or 24(Words24) words
mnemonic, err := bip.GenerateMnemonic(bip39.Words24)
fmt.Println("mnemonic: ", mnemonic)
if err != nil {
t.Errorf(err.Error())
}
// passphrase: An optional passphrase used for seed derivation. Can be an empty string.
toSeed := bip39.ToSeed(mnemonic, "PASSPHRASE")
fmt.Println("seed: ", formating.BytesToHex(toSeed))
_ = bip39.ToSeed(mnemonic, "PASSPHRASE")

toEntropy, err := bip.MnemonicToEntropy(mnemonic)
if err != nil {
Expand Down
5 changes: 2 additions & 3 deletions test/hd_wallet_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package test

import (
"fmt"
"testing"

"github.com/mrtnetwork/bitcoin/address"
hdwallet "github.com/mrtnetwork/bitcoin/hd_wallet"
"testing"
)

func TestHDWallet(t *testing.T) {
Expand Down Expand Up @@ -72,7 +72,6 @@ func TestHDWallet(t *testing.T) {
}

p2wsh := publicKey.ToP2WSHAddress().Show(network)
fmt.Println("p2wsh: ", p2wsh)
if p2wsh != p2wshPublicWallet {
t.Errorf("Expected %v, but got %v", p2wshPublicWallet, p2wsh)
}
Expand Down
3 changes: 1 addition & 2 deletions test/keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func TestP2pkhAddresses(t *testing.T) {
if err == nil {
fmt.Println(tx.Program().Hash160 == hash160)
} else {
print(err.Error())
t.Errorf(err.Error())
}

})
Expand Down Expand Up @@ -234,7 +234,6 @@ func TestP2trAddresses(t *testing.T) {
t.Run("t7", func(t *testing.T) {
pub := privOdd.GetPublic()
program := pub.ToTaprootAddress().Program().Program
fmt.Println("program: ", program)
if !strings.EqualFold(program, correctOddTweakedPk) {
t.Errorf("Expected %v, but got %v", correctOddTweakedPk, program)
}
Expand Down
Loading

0 comments on commit e37a7a8

Please sign in to comment.