txsort: Convert to package

This converts the txsort code into a separate package and renames
'TxSort' and 'IsTxSorted' to 'Sort' an `IsSorted`, respectively.

It also adds a 'doc.go' and 'README.md' so it is consistent with the
other packages.
This commit is contained in:
Dave Collins 2015-10-23 04:09:09 -05:00
parent 5fd45e8085
commit 98fd0a0661
4 changed files with 83 additions and 34 deletions

44
txsort/README.md Normal file
View file

@ -0,0 +1,44 @@
txsort
======
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)]
(https://travis-ci.org/btcsuite/btcutil) [![ISC License]
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
Package txsort provides the transaction sorting according to BIPLI01.
BIPLI01 defines a standard lexicographical sort order of transaction inputs and
outputs. This is useful to standardize transactions for faster multi-party
agreement as well as preventing information leaks in a single-party use case.
The BIP goes into more detail, but for a quick and simplistic overview, the
order for inputs is defined as first sorting on the previous output hash and
then on the index as a tie breaker. The order for outputs is defined as first
sorting on the amount and then on the raw public key script bytes as a tie
breaker.
A comprehensive suite of tests is provided to ensure proper functionality.
## Documentation
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)]
(http://godoc.org/github.com/btcsuite/btcutil/txsort)
Full `go doc` style documentation for the project can be viewed online without
installing this package by using the GoDoc site here:
http://godoc.org/github.com/btcsuite/btcutil/txsort
You can also view the documentation locally once the package is installed with
the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
http://localhost:6060/pkg/github.com/btcsuite/btcutil/txsort
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil/txsort
```
## License
Package txsort is licensed under the [copyfree](http://copyfree.org) ISC
License.

20
txsort/doc.go Normal file
View file

@ -0,0 +1,20 @@
// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
Package txsort provides the transaction sorting according to BIPLI01.
Overview
BIPLI01 defines a standard lexicographical sort order of transaction inputs and
outputs. This is useful to standardize transactions for faster multi-party
agreement as well as preventing information leaks in a single-party use case.
The BIP goes into more detail, but for a quick and simplistic overview, the
order for inputs is defined as first sorting on the previous output hash and
then on the index as a tie breaker. The order for outputs is defined as first
sorting on the amount and then on the raw public key script bytes as a tie
breaker.
*/
package txsort

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package btcutil package txsort
import ( import (
"bytes" "bytes"
@ -15,19 +15,19 @@ import (
// Provides functions for sorting tx inputs and outputs according to BIP LI01 // Provides functions for sorting tx inputs and outputs according to BIP LI01
// (https://github.com/kristovatlas/rfc/blob/master/bips/bip-li01.mediawiki) // (https://github.com/kristovatlas/rfc/blob/master/bips/bip-li01.mediawiki)
// TxSort sorts the inputs and outputs of a tx based on BIP LI01 // Sort sorts the inputs and outputs of a tx based on BIP LI01
// It does not modify the transaction given, but returns a new copy // It does not modify the transaction given, but returns a new copy
// which has been sorted and may have a different txid. // which has been sorted and may have a different txid.
func TxSort(tx *wire.MsgTx) *wire.MsgTx { func Sort(tx *wire.MsgTx) *wire.MsgTx {
txCopy := tx.Copy() txCopy := tx.Copy()
sort.Sort(sortableInputSlice(txCopy.TxIn)) sort.Sort(sortableInputSlice(txCopy.TxIn))
sort.Sort(sortableOutputSlice(txCopy.TxOut)) sort.Sort(sortableOutputSlice(txCopy.TxOut))
return txCopy return txCopy
} }
// TxIsSorted checks whether tx has inputs and outputs sorted according // IsSorted checks whether tx has inputs and outputs sorted according
// to BIP LI01. // to BIP LI01.
func TxIsSorted(tx *wire.MsgTx) bool { func IsSorted(tx *wire.MsgTx) bool {
if !sort.IsSorted(sortableInputSlice(tx.TxIn)) { if !sort.IsSorted(sortableInputSlice(tx.TxIn)) {
return false return false
} }

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package btcutil_test package txsort_test
import ( import (
"bytes" "bytes"
@ -10,26 +10,11 @@ import (
"testing" "testing"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/txsort"
) )
// TestSortTx tests SortTx function // TestSort tests Sort function
func TestSortTx(t *testing.T) { func TestSort(t *testing.T) {
// Use block 100,000 transaction 1. Already sorted.
testTx := Block100000.Transactions[1]
sortedTx := btcutil.TxSort(testTx)
testTxid := testTx.TxSha()
sortedTxid := sortedTx.TxSha()
if !testTxid.IsEqual(&sortedTxid) {
t.Errorf("Sorted TxSha mismatch - got %v, want %v",
testTxid.String(), sortedTxid.String())
}
if !btcutil.TxIsSorted(testTx) {
t.Errorf("testTx %v is sorted but reported as unsorted",
testTxid.String())
}
// Example 1 0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3 // Example 1 0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3
// test transaction 0a6a357e... which is the first test case of BIPLI01 // test transaction 0a6a357e... which is the first test case of BIPLI01
li01Tx1bytes, err := hex.DecodeString(LI01Hex1) li01Tx1bytes, err := hex.DecodeString(LI01Hex1)
@ -43,11 +28,11 @@ func TestSortTx(t *testing.T) {
t.Errorf("Failed to Deserialize li01Tx from byte slice") t.Errorf("Failed to Deserialize li01Tx from byte slice")
} }
if btcutil.TxIsSorted(&li01Tx1) { if txsort.IsSorted(&li01Tx1) {
t.Errorf("LI01 Test Transaction 1 seen as sorted, but isn't") t.Errorf("LI01 Test Transaction 1 seen as sorted, but isn't")
} }
li01Tx1Sorted := btcutil.TxSort(&li01Tx1) li01Tx1Sorted := txsort.Sort(&li01Tx1)
// txid of 0a6a357e... becomes 839503c... when sorted // txid of 0a6a357e... becomes 839503c... when sorted
wantSha := newShaHashFromStr("839503cb611a3e3734bd521c608f881be2293ff77b7384057ab994c794fce623") wantSha := newShaHashFromStr("839503cb611a3e3734bd521c608f881be2293ff77b7384057ab994c794fce623")
@ -78,11 +63,11 @@ func TestSortTx(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to Deserialize li01Tx from byte slice") t.Errorf("Failed to Deserialize li01Tx from byte slice")
} }
if !btcutil.TxIsSorted(&li01Tx2) { if !txsort.IsSorted(&li01Tx2) {
t.Errorf("LI01 Test Transaction 2 seen as unsorted, but it is sorted") t.Errorf("LI01 Test Transaction 2 seen as unsorted, but it is sorted")
} }
li01Tx2Sorted := btcutil.TxSort(&li01Tx2) li01Tx2Sorted := txsort.Sort(&li01Tx2)
// txid of 28204cad... stays the same when sorted // txid of 28204cad... stays the same when sorted
wantSha = newShaHashFromStr("28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f") wantSha = newShaHashFromStr("28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")
@ -104,11 +89,11 @@ func TestSortTx(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to Deserialize li01Tx3 from byte slice") t.Errorf("Failed to Deserialize li01Tx3 from byte slice")
} }
if btcutil.TxIsSorted(&li01Tx3) { if txsort.IsSorted(&li01Tx3) {
t.Errorf("LI01 Test Transaction 3 seen as sorted, but isn't") t.Errorf("LI01 Test Transaction 3 seen as sorted, but isn't")
} }
li01Tx3Sorted := btcutil.TxSort(&li01Tx3) li01Tx3Sorted := txsort.Sort(&li01Tx3)
// txid of 8131ffb0... changes to 0a8c246... when sorted // txid of 8131ffb0... changes to 0a8c246... when sorted
wantSha = newShaHashFromStr("0a8c246c55f6b82f094d211f4f57167bf2ea4898741d218b09bdb2536fd8d13f") wantSha = newShaHashFromStr("0a8c246c55f6b82f094d211f4f57167bf2ea4898741d218b09bdb2536fd8d13f")
@ -130,11 +115,11 @@ func TestSortTx(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to Deserialize li01Tx4 from byte slice") t.Errorf("Failed to Deserialize li01Tx4 from byte slice")
} }
if btcutil.TxIsSorted(&li01Tx4) { if txsort.IsSorted(&li01Tx4) {
t.Errorf("LI01 Test Transaction 4 seen as sorted, but isn't") t.Errorf("LI01 Test Transaction 4 seen as sorted, but isn't")
} }
li01Tx4Sorted := btcutil.TxSort(&li01Tx4) li01Tx4Sorted := txsort.Sort(&li01Tx4)
// txid of 8131ffb0... changes to 0a8c246... when sorted // txid of 8131ffb0... changes to 0a8c246... when sorted
wantSha = newShaHashFromStr("a3196553b928b0b6154b002fa9a1ce875adabc486fedaaaf4c17430fd4486329") wantSha = newShaHashFromStr("a3196553b928b0b6154b002fa9a1ce875adabc486fedaaaf4c17430fd4486329")
@ -156,11 +141,11 @@ func TestSortTx(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to Deserialize li01Tx5 from byte slice") t.Errorf("Failed to Deserialize li01Tx5 from byte slice")
} }
if btcutil.TxIsSorted(&li01Tx5) { if txsort.IsSorted(&li01Tx5) {
t.Errorf("LI01 Test Transaction 5 seen as sorted, but isn't") t.Errorf("LI01 Test Transaction 5 seen as sorted, but isn't")
} }
li01Tx5Sorted := btcutil.TxSort(&li01Tx5) li01Tx5Sorted := txsort.Sort(&li01Tx5)
// txid of ff85e8f... changes to 9a6c247... when sorted // txid of ff85e8f... changes to 9a6c247... when sorted
wantSha = newShaHashFromStr("9a6c24746de024f77cac9b2138694f11101d1c66289261224ca52a25155a7c94") wantSha = newShaHashFromStr("9a6c24746de024f77cac9b2138694f11101d1c66289261224ca52a25155a7c94")