You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
12 KiB

7 years ago
7 years ago
7 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "crypto/sha256"
  5. "errors"
  6. "fmt"
  7. "sort"
  8. abci "github.com/tendermint/tendermint/abci/types"
  9. "github.com/tendermint/tendermint/crypto/merkle"
  10. "github.com/tendermint/tendermint/crypto/tmhash"
  11. tmbytes "github.com/tendermint/tendermint/libs/bytes"
  12. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  13. )
  14. // Tx is an arbitrary byte array.
  15. // NOTE: Tx has no types at this level, so when wire encoded it's just length-prefixed.
  16. // Might we want types here ?
  17. type Tx []byte
  18. // Key produces a fixed-length key for use in indexing.
  19. func (tx Tx) Key() TxKey { return sha256.Sum256(tx) }
  20. // Hash computes the TMHASH hash of the wire encoded transaction.
  21. func (tx Tx) Hash() []byte { return tmhash.Sum(tx) }
  22. // String returns the hex-encoded transaction as a string.
  23. func (tx Tx) String() string { return fmt.Sprintf("Tx{%X}", []byte(tx)) }
  24. // Txs is a slice of Tx.
  25. type Txs []Tx
  26. // Hash returns the Merkle root hash of the transaction hashes.
  27. // i.e. the leaves of the tree are the hashes of the txs.
  28. func (txs Txs) Hash() []byte {
  29. hl := txs.hashList()
  30. return merkle.HashFromByteSlices(hl)
  31. }
  32. // Index returns the index of this transaction in the list, or -1 if not found
  33. func (txs Txs) Index(tx Tx) int {
  34. for i := range txs {
  35. if bytes.Equal(txs[i], tx) {
  36. return i
  37. }
  38. }
  39. return -1
  40. }
  41. // IndexByHash returns the index of this transaction hash in the list, or -1 if not found
  42. func (txs Txs) IndexByHash(hash []byte) int {
  43. for i := range txs {
  44. if bytes.Equal(txs[i].Hash(), hash) {
  45. return i
  46. }
  47. }
  48. return -1
  49. }
  50. func (txs Txs) Proof(i int) TxProof {
  51. hl := txs.hashList()
  52. root, proofs := merkle.ProofsFromByteSlices(hl)
  53. return TxProof{
  54. RootHash: root,
  55. Data: txs[i],
  56. Proof: *proofs[i],
  57. }
  58. }
  59. func (txs Txs) hashList() [][]byte {
  60. hl := make([][]byte, len(txs))
  61. for i := 0; i < len(txs); i++ {
  62. hl[i] = txs[i].Hash()
  63. }
  64. return hl
  65. }
  66. // Txs is a slice of transactions. Sorting a Txs value orders the transactions
  67. // lexicographically.
  68. func (txs Txs) Len() int { return len(txs) }
  69. func (txs Txs) Swap(i, j int) { txs[i], txs[j] = txs[j], txs[i] }
  70. func (txs Txs) Less(i, j int) bool {
  71. return bytes.Compare(txs[i], txs[j]) == -1
  72. }
  73. // ToSliceOfBytes converts a Txs to slice of byte slices.
  74. func (txs Txs) ToSliceOfBytes() [][]byte {
  75. txBzs := make([][]byte, len(txs))
  76. for i := 0; i < len(txs); i++ {
  77. txBzs[i] = txs[i]
  78. }
  79. return txBzs
  80. }
  81. // TxRecordSet contains indexes into an underlying set of transactions.
  82. // These indexes are useful for validating and working with a list of TxRecords
  83. // from the PrepareProposal response.
  84. //
  85. // Only one copy of the original data is referenced by all of the indexes but a
  86. // transaction may appear in multiple indexes.
  87. type TxRecordSet struct {
  88. // all holds the complete list of all transactions from the original list of
  89. // TxRecords.
  90. all Txs
  91. // included is an index of the transactions that will be included in the block
  92. // and is constructed from the list of both added and unmodified transactions.
  93. // included maintains the original order that the transactions were present
  94. // in the list of TxRecords.
  95. included Txs
  96. // added, unmodified, removed, and unknown are indexes for each of the actions
  97. // that may be supplied with a transaction.
  98. //
  99. // Because each transaction only has one action, it can be referenced by
  100. // at most 3 indexes in this data structure: the action-specific index, the
  101. // included index, and the all index.
  102. added Txs
  103. unmodified Txs
  104. removed Txs
  105. unknown Txs
  106. }
  107. // NewTxRecordSet constructs a new set from the given transaction records.
  108. // The contents of the input transactions are shared by the set, and must not
  109. // be modified during the lifetime of the set.
  110. func NewTxRecordSet(trs []*abci.TxRecord) TxRecordSet {
  111. txrSet := TxRecordSet{
  112. all: make([]Tx, len(trs)),
  113. }
  114. for i, tr := range trs {
  115. txrSet.all[i] = Tx(tr.Tx)
  116. // The following set of assignments do not allocate new []byte, they create
  117. // pointers to the already allocated slice.
  118. switch tr.GetAction() {
  119. case abci.TxRecord_UNKNOWN:
  120. txrSet.unknown = append(txrSet.unknown, txrSet.all[i])
  121. case abci.TxRecord_UNMODIFIED:
  122. txrSet.unmodified = append(txrSet.unmodified, txrSet.all[i])
  123. txrSet.included = append(txrSet.included, txrSet.all[i])
  124. case abci.TxRecord_ADDED:
  125. txrSet.added = append(txrSet.added, txrSet.all[i])
  126. txrSet.included = append(txrSet.included, txrSet.all[i])
  127. case abci.TxRecord_REMOVED:
  128. txrSet.removed = append(txrSet.removed, txrSet.all[i])
  129. }
  130. }
  131. return txrSet
  132. }
  133. // AddedTxs returns the transactions marked for inclusion in a block. This
  134. // list maintains the order that the transactions were included in the list of
  135. // TxRecords that were used to construct the TxRecordSet.
  136. func (t TxRecordSet) IncludedTxs() []Tx {
  137. return t.included
  138. }
  139. // AddedTxs returns the transactions added by the application.
  140. func (t TxRecordSet) AddedTxs() []Tx {
  141. return t.added
  142. }
  143. // RemovedTxs returns the transactions marked for removal by the application.
  144. func (t TxRecordSet) RemovedTxs() []Tx {
  145. return t.removed
  146. }
  147. // Validate checks that the record set was correctly constructed from the original
  148. // list of transactions.
  149. func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error {
  150. if len(t.unknown) > 0 {
  151. return fmt.Errorf("%d transactions marked unknown (first unknown hash: %x)", len(t.unknown), t.unknown[0].Hash())
  152. }
  153. // The following validation logic performs a set of sorts on the data in the TxRecordSet indexes.
  154. // It sorts the original transaction list, otxs, once.
  155. // It sorts the new transaction list twice: once when sorting 'all', the total list,
  156. // and once by sorting the set of the added, removed, and unmodified transactions indexes,
  157. // which, when combined, comprise the complete list of modified transactions.
  158. //
  159. // The original list is iterated once and the modified list is iterated multiple times,
  160. // one time alongside each of the 3 indexes for a total of 4 iterations of the modified list.
  161. // Asymptotically, this yields a total runtime of O(N*log(N) + N + 2*M*log(M) + 4*M),
  162. // in the input size of the original list and the input size of the new list respectively.
  163. // A 2 * M performance gain is possible by iterating all of the indexes simultaneously
  164. // alongside the full list, but the multiple iterations were preferred to be more
  165. // readable and maintainable.
  166. // Sort a copy of the complete transaction slice so we can check for
  167. // duplication. The copy is so we do not change the original ordering.
  168. // Only the slices are copied, the transaction contents are shared.
  169. allCopy := sortedCopy(t.all)
  170. var size int64
  171. for i, cur := range allCopy {
  172. size += int64(len(cur))
  173. if size > maxSizeBytes {
  174. return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes)
  175. }
  176. // allCopy is sorted, so any duplicated data will be adjacent.
  177. if i+1 < len(allCopy) && bytes.Equal(cur, allCopy[i+1]) {
  178. return fmt.Errorf("found duplicate transaction with hash: %x", cur.Hash())
  179. }
  180. }
  181. // create copies of each of the action-specific indexes so that order of the original
  182. // indexes can be preserved.
  183. addedCopy := sortedCopy(t.added)
  184. removedCopy := sortedCopy(t.removed)
  185. unmodifiedCopy := sortedCopy(t.unmodified)
  186. // make a defensive copy of otxs so that the order of
  187. // the caller's data is not altered.
  188. otxsCopy := sortedCopy(otxs)
  189. if ix, ok := containsAllTxs(otxsCopy, unmodifiedCopy); !ok {
  190. return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", unmodifiedCopy[ix].Hash())
  191. }
  192. if ix, ok := containsAllTxs(otxsCopy, removedCopy); !ok {
  193. return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", removedCopy[ix].Hash())
  194. }
  195. if ix, ok := containsAnyTxs(otxsCopy, addedCopy); ok {
  196. return fmt.Errorf("existing transaction incorrectly marked as added, transaction hash: %x", addedCopy[ix].Hash())
  197. }
  198. return nil
  199. }
  200. func sortedCopy(txs Txs) Txs {
  201. cp := make(Txs, len(txs))
  202. copy(cp, txs)
  203. sort.Sort(cp)
  204. return cp
  205. }
  206. // containsAnyTxs checks that list a contains one of the transactions in list
  207. // b. If a match is found, the index in b of the matching transaction is returned.
  208. // Both lists must be sorted.
  209. func containsAnyTxs(a, b []Tx) (int, bool) {
  210. aix, bix := 0, 0
  211. nextA:
  212. for ; aix < len(a); aix++ {
  213. for bix < len(b) {
  214. switch bytes.Compare(b[bix], a[aix]) {
  215. case 0:
  216. return bix, true
  217. case -1:
  218. bix++
  219. // we've reached the end of b, and the last value in b was
  220. // smaller than the value under the iterator of a.
  221. // a's values never get smaller, so we know there are no more matches
  222. // in the list. We can terminate the iteration here.
  223. if bix == len(b) {
  224. return -1, false
  225. }
  226. case 1:
  227. continue nextA
  228. }
  229. }
  230. }
  231. return -1, false
  232. }
  233. // containsAllTxs checks that super contains all of the transactions in the sub
  234. // list. If not all values in sub are present in super, the index in sub of the
  235. // first Tx absent from super is returned.
  236. func containsAllTxs(super, sub []Tx) (int, bool) {
  237. // The following iteration assumes sorted lists.
  238. // The checks ensure that all the values in the sorted sub list are present in the sorted super list.
  239. //
  240. // We compare the value under the sub iterator to the value
  241. // under the super iterator. If they match, we advance the
  242. // sub iterator one position. If they don't match, then the value under
  243. // the sub iterator should be greater.
  244. // If it is not, then there is a value in the the sub list that is not present in the
  245. // super list.
  246. subIx := 0
  247. for _, cur := range super {
  248. if subIx == len(sub) {
  249. return -1, true
  250. }
  251. switch bytes.Compare(sub[subIx], cur) {
  252. case 0:
  253. subIx++
  254. case -1:
  255. return subIx, false
  256. }
  257. }
  258. // Check that the loop visited all values of the transactions from sub.
  259. // If it did not, then there are values present in these indexes that were not
  260. // present in the super list of transactions.
  261. if subIx != len(sub) {
  262. return subIx, false
  263. }
  264. return -1, true
  265. }
  266. // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree.
  267. type TxProof struct {
  268. RootHash tmbytes.HexBytes `json:"root_hash"`
  269. Data Tx `json:"data"`
  270. Proof merkle.Proof `json:"proof"`
  271. }
  272. // Leaf returns the hash(tx), which is the leaf in the merkle tree which this proof refers to.
  273. func (tp TxProof) Leaf() []byte {
  274. return tp.Data.Hash()
  275. }
  276. // Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument,
  277. // and if the proof is internally consistent. Otherwise, it returns a sensible error.
  278. func (tp TxProof) Validate(dataHash []byte) error {
  279. if !bytes.Equal(dataHash, tp.RootHash) {
  280. return errors.New("proof matches different data hash")
  281. }
  282. if tp.Proof.Index < 0 {
  283. return errors.New("proof index cannot be negative")
  284. }
  285. if tp.Proof.Total <= 0 {
  286. return errors.New("proof total must be positive")
  287. }
  288. valid := tp.Proof.Verify(tp.RootHash, tp.Leaf())
  289. if valid != nil {
  290. return errors.New("proof is not internally consistent")
  291. }
  292. return nil
  293. }
  294. func (tp TxProof) ToProto() tmproto.TxProof {
  295. pbProof := tp.Proof.ToProto()
  296. pbtp := tmproto.TxProof{
  297. RootHash: tp.RootHash,
  298. Data: tp.Data,
  299. Proof: pbProof,
  300. }
  301. return pbtp
  302. }
  303. func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) {
  304. pbProof, err := merkle.ProofFromProto(pb.Proof)
  305. if err != nil {
  306. return TxProof{}, err
  307. }
  308. pbtp := TxProof{
  309. RootHash: pb.RootHash,
  310. Data: pb.Data,
  311. Proof: *pbProof,
  312. }
  313. return pbtp, nil
  314. }
  315. // ComputeProtoSizeForTxs wraps the transactions in tmproto.Data{} and calculates the size.
  316. // https://developers.google.com/protocol-buffers/docs/encoding
  317. func ComputeProtoSizeForTxs(txs []Tx) int64 {
  318. data := Data{Txs: txs}
  319. pdData := data.ToProto()
  320. return int64(pdData.Size())
  321. }