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.

347 lines
8.7 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "strings"
  7. "time"
  8. acm "github.com/tendermint/tendermint/account"
  9. . "github.com/tendermint/tendermint/common"
  10. "github.com/tendermint/tendermint/merkle"
  11. "github.com/tendermint/tendermint/wire"
  12. )
  13. type Block struct {
  14. *Header `json:"header"`
  15. *Data `json:"data"`
  16. LastValidation *Validation `json:"last_validation"`
  17. }
  18. // Basic validation that doesn't involve state data.
  19. func (b *Block) ValidateBasic(chainID string, lastBlockHeight int, lastBlockHash []byte,
  20. lastBlockParts PartSetHeader, lastBlockTime time.Time) error {
  21. if b.ChainID != chainID {
  22. return errors.New(Fmt("Wrong Block.Header.ChainID. Expected %v, got %v", chainID, b.ChainID))
  23. }
  24. if b.Height != lastBlockHeight+1 {
  25. return errors.New(Fmt("Wrong Block.Header.Height. Expected %v, got %v", lastBlockHeight+1, b.Height))
  26. }
  27. /* TODO: Determine bounds for Time
  28. See blockchain/reactor "stopSyncingDurationMinutes"
  29. if !b.Time.After(lastBlockTime) {
  30. return errors.New("Invalid Block.Header.Time")
  31. }
  32. */
  33. // TODO: validate Fees
  34. if b.NumTxs != len(b.Data.Txs) {
  35. return errors.New(Fmt("Wrong Block.Header.NumTxs. Expected %v, got %v", len(b.Data.Txs), b.NumTxs))
  36. }
  37. if !bytes.Equal(b.LastBlockHash, lastBlockHash) {
  38. return errors.New(Fmt("Wrong Block.Header.LastBlockHash. Expected %X, got %X", lastBlockHash, b.LastBlockHash))
  39. }
  40. if !b.LastBlockParts.Equals(lastBlockParts) {
  41. return errors.New(Fmt("Wrong Block.Header.LastBlockParts. Expected %v, got %v", lastBlockParts, b.LastBlockParts))
  42. }
  43. if !bytes.Equal(b.LastValidationHash, b.LastValidation.Hash()) {
  44. return errors.New(Fmt("Wrong Block.Header.LastValidationHash. Expected %X, got %X", b.LastValidationHash, b.LastValidation.Hash()))
  45. }
  46. if b.Header.Height != 1 {
  47. if err := b.LastValidation.ValidateBasic(); err != nil {
  48. return err
  49. }
  50. }
  51. if !bytes.Equal(b.DataHash, b.Data.Hash()) {
  52. return errors.New(Fmt("Wrong Block.Header.DataHash. Expected %X, got %X", b.DataHash, b.Data.Hash()))
  53. }
  54. // NOTE: the StateHash is validated later.
  55. return nil
  56. }
  57. func (b *Block) FillHeader() {
  58. b.LastValidationHash = b.LastValidation.Hash()
  59. b.DataHash = b.Data.Hash()
  60. }
  61. // Computes and returns the block hash.
  62. // If the block is incomplete (e.g. missing Header.StateHash)
  63. // then the hash is nil, to prevent the usage of that hash.
  64. func (b *Block) Hash() []byte {
  65. if b.Header == nil || b.Data == nil || b.LastValidation == nil {
  66. return nil
  67. }
  68. b.FillHeader()
  69. return b.Header.Hash()
  70. }
  71. func (b *Block) MakePartSet() *PartSet {
  72. return NewPartSetFromData(wire.BinaryBytes(b))
  73. }
  74. // Convenience.
  75. // A nil block never hashes to anything.
  76. // Nothing hashes to a nil hash.
  77. func (b *Block) HashesTo(hash []byte) bool {
  78. if len(hash) == 0 {
  79. return false
  80. }
  81. if b == nil {
  82. return false
  83. }
  84. return bytes.Equal(b.Hash(), hash)
  85. }
  86. func (b *Block) String() string {
  87. return b.StringIndented("")
  88. }
  89. func (b *Block) StringIndented(indent string) string {
  90. if b == nil {
  91. return "nil-Block"
  92. }
  93. return fmt.Sprintf(`Block{
  94. %s %v
  95. %s %v
  96. %s %v
  97. %s}#%X`,
  98. indent, b.Header.StringIndented(indent+" "),
  99. indent, b.Data.StringIndented(indent+" "),
  100. indent, b.LastValidation.StringIndented(indent+" "),
  101. indent, b.Hash())
  102. }
  103. func (b *Block) StringShort() string {
  104. if b == nil {
  105. return "nil-Block"
  106. } else {
  107. return fmt.Sprintf("Block#%X", b.Hash())
  108. }
  109. }
  110. //-----------------------------------------------------------------------------
  111. type Header struct {
  112. ChainID string `json:"chain_id"`
  113. Height int `json:"height"`
  114. Time time.Time `json:"time"`
  115. Fees int64 `json:"fees"`
  116. NumTxs int `json:"num_txs"`
  117. LastBlockHash []byte `json:"last_block_hash"`
  118. LastBlockParts PartSetHeader `json:"last_block_parts"`
  119. LastValidationHash []byte `json:"last_validation_hash"`
  120. DataHash []byte `json:"data_hash"`
  121. StateHash []byte `json:"state_hash"`
  122. }
  123. // NOTE: hash is nil if required fields are missing.
  124. func (h *Header) Hash() []byte {
  125. if len(h.StateHash) == 0 {
  126. return nil
  127. }
  128. return merkle.SimpleHashFromMap(map[string]interface{}{
  129. "ChainID": h.ChainID,
  130. "Height": h.Height,
  131. "Time": h.Time,
  132. "Fees": h.Fees,
  133. "NumTxs": h.NumTxs,
  134. "LastBlock": h.LastBlockHash,
  135. "LastBlockParts": h.LastBlockParts,
  136. "LastValidation": h.LastValidationHash,
  137. "Data": h.DataHash,
  138. "State": h.StateHash,
  139. })
  140. }
  141. func (h *Header) StringIndented(indent string) string {
  142. if h == nil {
  143. return "nil-Header"
  144. }
  145. return fmt.Sprintf(`Header{
  146. %s ChainID: %v
  147. %s Height: %v
  148. %s Time: %v
  149. %s Fees: %v
  150. %s NumTxs: %v
  151. %s LastBlockHash: %X
  152. %s LastBlockParts: %v
  153. %s StateHash: %X
  154. %s}#%X`,
  155. indent, h.ChainID,
  156. indent, h.Height,
  157. indent, h.Time,
  158. indent, h.Fees,
  159. indent, h.NumTxs,
  160. indent, h.LastBlockHash,
  161. indent, h.LastBlockParts,
  162. indent, h.StateHash,
  163. indent, h.Hash())
  164. }
  165. //-------------------------------------
  166. // NOTE: Validation is empty for height 1, but never nil.
  167. type Validation struct {
  168. // NOTE: The Precommits are in order of address to preserve the bonded ValidatorSet order.
  169. // Any peer with a block can gossip precommits by index with a peer without recalculating the
  170. // active ValidatorSet.
  171. Precommits []*Vote `json:"precommits"`
  172. // Volatile
  173. firstPrecommit *Vote
  174. hash []byte
  175. bitArray *BitArray
  176. }
  177. func (v *Validation) FirstPrecommit() *Vote {
  178. if len(v.Precommits) == 0 {
  179. return nil
  180. }
  181. if v.firstPrecommit != nil {
  182. return v.firstPrecommit
  183. }
  184. for _, precommit := range v.Precommits {
  185. if precommit != nil {
  186. v.firstPrecommit = precommit
  187. return precommit
  188. }
  189. }
  190. return nil
  191. }
  192. func (v *Validation) Height() int {
  193. if len(v.Precommits) == 0 {
  194. return 0
  195. }
  196. return v.FirstPrecommit().Height
  197. }
  198. func (v *Validation) Round() int {
  199. if len(v.Precommits) == 0 {
  200. return 0
  201. }
  202. return v.FirstPrecommit().Round
  203. }
  204. func (v *Validation) Type() byte {
  205. return VoteTypePrecommit
  206. }
  207. func (v *Validation) Size() int {
  208. if v == nil {
  209. return 0
  210. }
  211. return len(v.Precommits)
  212. }
  213. func (v *Validation) BitArray() *BitArray {
  214. if v.bitArray == nil {
  215. v.bitArray = NewBitArray(len(v.Precommits))
  216. for i, precommit := range v.Precommits {
  217. v.bitArray.SetIndex(i, precommit != nil)
  218. }
  219. }
  220. return v.bitArray
  221. }
  222. func (v *Validation) GetByIndex(index int) *Vote {
  223. return v.Precommits[index]
  224. }
  225. func (v *Validation) IsCommit() bool {
  226. if len(v.Precommits) == 0 {
  227. return false
  228. }
  229. return true
  230. }
  231. func (v *Validation) ValidateBasic() error {
  232. if len(v.Precommits) == 0 {
  233. return errors.New("No precommits in validation")
  234. }
  235. height, round := v.Height(), v.Round()
  236. for _, precommit := range v.Precommits {
  237. // It's OK for precommits to be missing.
  238. if precommit == nil {
  239. continue
  240. }
  241. // Ensure that all votes are precommits
  242. if precommit.Type != VoteTypePrecommit {
  243. return fmt.Errorf("Invalid validation vote. Expected precommit, got %v",
  244. precommit.Type)
  245. }
  246. // Ensure that all heights are the same
  247. if precommit.Height != height {
  248. return fmt.Errorf("Invalid validation precommit height. Expected %v, got %v",
  249. height, precommit.Height)
  250. }
  251. // Ensure that all rounds are the same
  252. if precommit.Round != round {
  253. return fmt.Errorf("Invalid validation precommit round. Expected %v, got %v",
  254. round, precommit.Round)
  255. }
  256. }
  257. return nil
  258. }
  259. func (v *Validation) Hash() []byte {
  260. if v.hash == nil {
  261. bs := make([]interface{}, len(v.Precommits))
  262. for i, precommit := range v.Precommits {
  263. bs[i] = precommit
  264. }
  265. v.hash = merkle.SimpleHashFromBinaries(bs)
  266. }
  267. return v.hash
  268. }
  269. func (v *Validation) StringIndented(indent string) string {
  270. if v == nil {
  271. return "nil-Validation"
  272. }
  273. precommitStrings := make([]string, len(v.Precommits))
  274. for i, precommit := range v.Precommits {
  275. precommitStrings[i] = precommit.String()
  276. }
  277. return fmt.Sprintf(`Validation{
  278. %s Precommits: %v
  279. %s}#%X`,
  280. indent, strings.Join(precommitStrings, "\n"+indent+" "),
  281. indent, v.hash)
  282. }
  283. //-----------------------------------------------------------------------------
  284. type Data struct {
  285. Txs []Tx `json:"txs"`
  286. // Volatile
  287. hash []byte
  288. }
  289. func (data *Data) Hash() []byte {
  290. if data.hash == nil {
  291. bs := make([]interface{}, len(data.Txs))
  292. for i, tx := range data.Txs {
  293. bs[i] = acm.SignBytes(config.GetString("chain_id"), tx)
  294. }
  295. data.hash = merkle.SimpleHashFromBinaries(bs) // NOTE: leaves are TxIDs.
  296. }
  297. return data.hash
  298. }
  299. func (data *Data) StringIndented(indent string) string {
  300. if data == nil {
  301. return "nil-Data"
  302. }
  303. txStrings := make([]string, len(data.Txs))
  304. for i, tx := range data.Txs {
  305. txStrings[i] = fmt.Sprintf("Tx:%v", tx)
  306. }
  307. return fmt.Sprintf(`Data{
  308. %s %v
  309. %s}#%X`,
  310. indent, strings.Join(txStrings, "\n"+indent+" "),
  311. indent, data.hash)
  312. }