mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-23 13:38:35 +00:00
94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
package transaction
|
|
|
|
import (
|
|
"sort"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
)
|
|
|
|
// Input represents a Transaction input (CoinReference).
|
|
type Input struct {
|
|
// The hash of the previous transaction.
|
|
PrevHash util.Uint256 `json:"txid"`
|
|
|
|
// The index of the previous transaction.
|
|
PrevIndex uint16 `json:"vout"`
|
|
}
|
|
|
|
// DecodeBinary implements Serializable interface.
|
|
func (in *Input) DecodeBinary(br *io.BinReader) {
|
|
br.ReadBytes(in.PrevHash[:])
|
|
in.PrevIndex = br.ReadU16LE()
|
|
}
|
|
|
|
// EncodeBinary implements Serializable interface.
|
|
func (in *Input) EncodeBinary(bw *io.BinWriter) {
|
|
bw.WriteBytes(in.PrevHash[:])
|
|
bw.WriteU16LE(in.PrevIndex)
|
|
}
|
|
|
|
// Cmp compares two Inputs by their hash and index allowing to make a set of
|
|
// transactions ordered.
|
|
func (in *Input) Cmp(other *Input) int {
|
|
hashcmp := in.PrevHash.CompareTo(other.PrevHash)
|
|
if hashcmp == 0 {
|
|
return int(in.PrevIndex) - int(other.PrevIndex)
|
|
}
|
|
return hashcmp
|
|
}
|
|
|
|
// MapInputsToSorted maps given slice of inputs into a new slice of pointers
|
|
// to inputs sorted by their PrevHash and PrevIndex.
|
|
func MapInputsToSorted(ins []Input) []*Input {
|
|
ptrs := make([]*Input, len(ins))
|
|
for i := range ins {
|
|
ptrs[i] = &ins[i]
|
|
}
|
|
sort.Slice(ptrs, func(i, j int) bool {
|
|
return ptrs[i].Cmp(ptrs[j]) < 0
|
|
})
|
|
return ptrs
|
|
}
|
|
|
|
// GroupInputsByPrevHash groups all TX inputs by their previous hash into
|
|
// several slices (which actually are subslices of one new slice with pointers).
|
|
// Each of these slices contains at least one element.
|
|
func GroupInputsByPrevHash(ins []Input) [][]*Input {
|
|
if len(ins) == 0 {
|
|
return nil
|
|
}
|
|
|
|
ptrs := MapInputsToSorted(ins)
|
|
var first int
|
|
res := make([][]*Input, 0)
|
|
currentHash := ptrs[0].PrevHash
|
|
|
|
for i := range ptrs {
|
|
if !currentHash.Equals(ptrs[i].PrevHash) {
|
|
res = append(res, ptrs[first:i])
|
|
first = i
|
|
currentHash = ptrs[i].PrevHash
|
|
}
|
|
}
|
|
res = append(res, ptrs[first:])
|
|
return res
|
|
}
|
|
|
|
// HaveDuplicateInputs checks inputs for duplicates and returns true if there are
|
|
// any.
|
|
func HaveDuplicateInputs(ins []Input) bool {
|
|
if len(ins) < 2 {
|
|
return false
|
|
}
|
|
if len(ins) == 2 {
|
|
return ins[0] == ins[1]
|
|
}
|
|
ptrs := MapInputsToSorted(ins)
|
|
for i := 1; i < len(ptrs); i++ {
|
|
if *ptrs[i] == *ptrs[i-1] {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|