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 }