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.

375 lines
12 KiB

7 years ago
7 years ago
7 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. // These allocations will be removed once Txs is switched to [][]byte,
  30. // ref #2603. This is because golang does not allow type casting slices without unsafe
  31. txBzs := make([][]byte, len(txs))
  32. for i := 0; i < len(txs); i++ {
  33. txBzs[i] = txs[i].Hash()
  34. }
  35. return merkle.HashFromByteSlices(txBzs)
  36. }
  37. // Index returns the index of this transaction in the list, or -1 if not found
  38. func (txs Txs) Index(tx Tx) int {
  39. for i := range txs {
  40. if bytes.Equal(txs[i], tx) {
  41. return i
  42. }
  43. }
  44. return -1
  45. }
  46. // IndexByHash returns the index of this transaction hash in the list, or -1 if not found
  47. func (txs Txs) IndexByHash(hash []byte) int {
  48. for i := range txs {
  49. if bytes.Equal(txs[i].Hash(), hash) {
  50. return i
  51. }
  52. }
  53. return -1
  54. }
  55. func (txs Txs) Len() int { return len(txs) }
  56. func (txs Txs) Swap(i, j int) { txs[i], txs[j] = txs[j], txs[i] }
  57. func (txs Txs) Less(i, j int) bool {
  58. return bytes.Compare(txs[i], txs[j]) == -1
  59. }
  60. // ToSliceOfBytes converts a Txs to slice of byte slices.
  61. //
  62. // NOTE: This method should become obsolete once Txs is switched to [][]byte.
  63. // ref: #2603
  64. // TODO This function is to disappear when TxRecord is introduced
  65. func (txs Txs) ToSliceOfBytes() [][]byte {
  66. txBzs := make([][]byte, len(txs))
  67. for i := 0; i < len(txs); i++ {
  68. txBzs[i] = txs[i]
  69. }
  70. return txBzs
  71. }
  72. // ToTxs converts a raw slice of byte slices into a Txs type.
  73. // TODO This function is to disappear when TxRecord is introduced
  74. func ToTxs(txs [][]byte) Txs {
  75. txBzs := make(Txs, len(txs))
  76. for i := 0; i < len(txs); i++ {
  77. txBzs[i] = txs[i]
  78. }
  79. return txBzs
  80. }
  81. // TxRecordsToTxs converts from the abci Tx type to the the Txs type.
  82. func TxRecordsToTxs(trs []*abci.TxRecord) Txs {
  83. txs := make([]Tx, len(trs))
  84. for i, tr := range trs {
  85. txs[i] = Tx(tr.Tx)
  86. }
  87. return txs
  88. }
  89. // TxRecordSet contains indexes into an underlying set of transactions.
  90. // These indexes are useful for validating and working with a list of TxRecords
  91. // from the PrepareProposal response.
  92. //
  93. // Only one copy of the original data is referenced by all of the indexes but a
  94. // transaction may appear in multiple indexes.
  95. type TxRecordSet struct {
  96. // all holds the complete list of all transactions from the original list of
  97. // TxRecords.
  98. all Txs
  99. // included is an index of the transactions that will be included in the block
  100. // and is constructed from the list of both added and unmodified transactions.
  101. // included maintains the original order that the transactions were present
  102. // in the list of TxRecords.
  103. included Txs
  104. // added, unmodified, removed, and unknown are indexes for each of the actions
  105. // that may be supplied with a transaction.
  106. //
  107. // Because each transaction only has one action, it can be referenced by
  108. // at most 3 indexes in this data structure: the action-specific index, the
  109. // included index, and the all index.
  110. added Txs
  111. unmodified Txs
  112. removed Txs
  113. unknown Txs
  114. }
  115. func NewTxRecordSet(trs []*abci.TxRecord) TxRecordSet {
  116. txrSet := TxRecordSet{}
  117. txrSet.all = make([]Tx, len(trs))
  118. for i, tr := range trs {
  119. // A single allocation is performed per transaction from the list of TxRecords
  120. // on the line below.
  121. txrSet.all[i] = Tx(tr.Tx)
  122. // The following set of assignments do not allocate new []byte, they create
  123. // pointers to the already allocated slice.
  124. switch tr.GetAction() {
  125. case abci.TxRecord_UNKNOWN:
  126. txrSet.unknown = append(txrSet.unknown, txrSet.all[i])
  127. case abci.TxRecord_UNMODIFIED:
  128. txrSet.unmodified = append(txrSet.unmodified, txrSet.all[i])
  129. txrSet.included = append(txrSet.included, txrSet.all[i])
  130. case abci.TxRecord_ADDED:
  131. txrSet.added = append(txrSet.added, txrSet.all[i])
  132. txrSet.included = append(txrSet.included, txrSet.all[i])
  133. case abci.TxRecord_REMOVED:
  134. txrSet.removed = append(txrSet.removed, txrSet.all[i])
  135. }
  136. }
  137. return txrSet
  138. }
  139. // GetAddedTxs returns the transactions marked for inclusion in a block. This
  140. // list maintains the order that the transactions were included in the list of
  141. // TxRecords that were used to construct the TxRecordSet.
  142. func (t TxRecordSet) GetIncludedTxs() []Tx {
  143. return t.included
  144. }
  145. // GetAddedTxs returns the transactions added by the application.
  146. func (t TxRecordSet) GetAddedTxs() []Tx {
  147. return t.added
  148. }
  149. // GetRemovedTxs returns the transactions marked for removal by the application.
  150. func (t TxRecordSet) GetRemovedTxs() []Tx {
  151. return t.removed
  152. }
  153. // Validate checks that the record set was correctly constructed from the original
  154. // list of transactions.
  155. func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error {
  156. if len(t.unknown) > 0 {
  157. return fmt.Errorf("transaction incorrectly marked as unknown, transaction hash: %x", t.unknown[0].Hash())
  158. }
  159. // The following validation logic performs a set of sorts on the data in the TxRecordSet indexes.
  160. // It sorts the original transaction list, otxs, once.
  161. // It sorts the new transaction list twice: once when sorting 'all', the total list,
  162. // and once by sorting the set of the added, removed, and unmodified transactions indexes,
  163. // which, when combined, comprise the complete list of transactions.
  164. //
  165. // The original list is iterated once and the modified list and set of indexes are
  166. // also iterated once each.
  167. // Asymptotically, this yields a total runtime of O(N*log(N) + N + 2*M*log(M) + 2*M),
  168. // in the input size of the original list and the input size of the new list respectively.
  169. // make a copy of the all index so that the original order of the all index
  170. // can be preserved.
  171. // does not copy the underlying data.
  172. allCopy := make([]Tx, len(t.all))
  173. copy(allCopy, t.all)
  174. sort.Sort(Txs(allCopy))
  175. var size int64
  176. for i := 0; i < len(allCopy); i++ {
  177. size += int64(len(allCopy[i]))
  178. if size > maxSizeBytes {
  179. return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes)
  180. }
  181. // allCopy is sorted, so any duplicated data will be adjacent.
  182. if i < len(allCopy)-1 && bytes.Equal(allCopy[i], allCopy[i+1]) {
  183. return fmt.Errorf("TxRecords contains duplicate transaction, transaction hash: %x", allCopy[i].Hash())
  184. }
  185. }
  186. // create copies of each of the action-specific indexes so that order of the original
  187. // indexes can be preserved.
  188. addedCopy := make([]Tx, len(t.added))
  189. copy(addedCopy, t.added)
  190. removedCopy := make([]Tx, len(t.removed))
  191. copy(removedCopy, t.removed)
  192. unmodifiedCopy := make([]Tx, len(t.unmodified))
  193. copy(unmodifiedCopy, t.unmodified)
  194. sort.Sort(otxs)
  195. sort.Sort(Txs(addedCopy))
  196. sort.Sort(Txs(removedCopy))
  197. sort.Sort(Txs(unmodifiedCopy))
  198. unmodifiedIdx, addedIdx, removedIdx := 0, 0, 0
  199. for i := 0; i < len(otxs); i++ {
  200. if addedIdx == len(addedCopy) &&
  201. removedIdx == len(removedCopy) &&
  202. unmodifiedIdx == len(unmodifiedCopy) {
  203. // we've reached the end of all of the sorted indexes without
  204. // detecting any issues.
  205. break
  206. }
  207. LOOP:
  208. // iterate over the sorted addedIndex until we reach a value that sorts
  209. // higher than the value we are examining in the original list.
  210. for addedIdx < len(addedCopy) {
  211. switch bytes.Compare(addedCopy[addedIdx], otxs[i]) {
  212. case 0:
  213. return fmt.Errorf("existing transaction incorrectly marked as added, transaction hash: %x", otxs[i].Hash())
  214. case -1:
  215. addedIdx++
  216. case 1:
  217. break LOOP
  218. }
  219. }
  220. // The following iterator checks work in the same way on the removed iterator
  221. // and the unmodified iterator. They check that all the values in the respective sorted
  222. // index are present in the original list.
  223. //
  224. // For the removed check, we compare the value under the removed iterator to the value
  225. // under the iterator for the total sorted list. If they match, we advance the
  226. // removed iterator one position. If they don't match, then the value under
  227. // the remove iterator should be greater.
  228. // If it is not, then there is a value in the the removed list that was not present in the
  229. // original list.
  230. //
  231. // The same logic applies for the unmodified check.
  232. if removedIdx < len(removedCopy) {
  233. switch bytes.Compare(removedCopy[removedIdx], otxs[i]) {
  234. case 0:
  235. removedIdx++
  236. case -1:
  237. return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", removedCopy[i].Hash())
  238. }
  239. }
  240. if unmodifiedIdx < len(unmodifiedCopy) {
  241. switch bytes.Compare(unmodifiedCopy[unmodifiedIdx], otxs[i]) {
  242. case 0:
  243. unmodifiedIdx++
  244. case -1:
  245. return fmt.Errorf("new transaction incorrectly marked as unmodified, transaction hash: %x", removedCopy[i].Hash())
  246. }
  247. }
  248. }
  249. // Check that the loop visited all values of the removed and unmodified transactions.
  250. // If it did not, then there are values present in these indexes that were not
  251. // present in the original list of transactions.
  252. if removedIdx != len(removedCopy) {
  253. return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", removedCopy[removedIdx].Hash())
  254. }
  255. if unmodifiedIdx != len(unmodifiedCopy) {
  256. return fmt.Errorf("new transaction incorrectly marked as unmodified, transaction hash: %x", unmodifiedCopy[unmodifiedIdx].Hash())
  257. }
  258. return nil
  259. }
  260. // TxsToTxRecords converts from a list of Txs to a list of TxRecords. All of the
  261. // resulting TxRecords are returned with the status TxRecord_UNMODIFIED.
  262. func TxsToTxRecords(txs []Tx) []*abci.TxRecord {
  263. trs := make([]*abci.TxRecord, len(txs))
  264. for i, tx := range txs {
  265. trs[i] = &abci.TxRecord{
  266. Action: abci.TxRecord_UNMODIFIED,
  267. Tx: tx,
  268. }
  269. }
  270. return trs
  271. }
  272. // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree.
  273. type TxProof struct {
  274. RootHash tmbytes.HexBytes `json:"root_hash"`
  275. Data Tx `json:"data"`
  276. Proof merkle.Proof `json:"proof"`
  277. }
  278. // Leaf returns the hash(tx), which is the leaf in the merkle tree which this proof refers to.
  279. func (tp TxProof) Leaf() []byte {
  280. return tp.Data.Hash()
  281. }
  282. // Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument,
  283. // and if the proof is internally consistent. Otherwise, it returns a sensible error.
  284. func (tp TxProof) Validate(dataHash []byte) error {
  285. if !bytes.Equal(dataHash, tp.RootHash) {
  286. return errors.New("proof matches different data hash")
  287. }
  288. if tp.Proof.Index < 0 {
  289. return errors.New("proof index cannot be negative")
  290. }
  291. if tp.Proof.Total <= 0 {
  292. return errors.New("proof total must be positive")
  293. }
  294. valid := tp.Proof.Verify(tp.RootHash, tp.Leaf())
  295. if valid != nil {
  296. return errors.New("proof is not internally consistent")
  297. }
  298. return nil
  299. }
  300. func (tp TxProof) ToProto() tmproto.TxProof {
  301. pbProof := tp.Proof.ToProto()
  302. pbtp := tmproto.TxProof{
  303. RootHash: tp.RootHash,
  304. Data: tp.Data,
  305. Proof: pbProof,
  306. }
  307. return pbtp
  308. }
  309. func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) {
  310. pbProof, err := merkle.ProofFromProto(pb.Proof)
  311. if err != nil {
  312. return TxProof{}, err
  313. }
  314. pbtp := TxProof{
  315. RootHash: pb.RootHash,
  316. Data: pb.Data,
  317. Proof: *pbProof,
  318. }
  319. return pbtp, nil
  320. }
  321. // ComputeProtoSizeForTxs wraps the transactions in tmproto.Data{} and calculates the size.
  322. // https://developers.google.com/protocol-buffers/docs/encoding
  323. func ComputeProtoSizeForTxs(txs []Tx) int64 {
  324. data := Data{Txs: txs}
  325. pdData := data.ToProto()
  326. return int64(pdData.Size())
  327. }