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.

299 lines
7.2 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
11 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "crypto/sha256"
  5. "errors"
  6. "fmt"
  7. "strings"
  8. "time"
  9. "github.com/tendermint/tendermint/account"
  10. "github.com/tendermint/tendermint/binary"
  11. . "github.com/tendermint/tendermint/common"
  12. "github.com/tendermint/tendermint/merkle"
  13. )
  14. type Block struct {
  15. *Header `json:"header"`
  16. *Validation `json:"validation"`
  17. *Data `json:"data"`
  18. }
  19. // Basic validation that doesn't involve state data.
  20. func (b *Block) ValidateBasic(chainID string, lastBlockHeight uint, lastBlockHash []byte,
  21. lastBlockParts PartSetHeader, lastBlockTime time.Time) error {
  22. if b.ChainID != chainID {
  23. return errors.New("Wrong Block.Header.ChainID")
  24. }
  25. if b.Height != lastBlockHeight+1 {
  26. return errors.New("Wrong Block.Header.Height")
  27. }
  28. if b.NumTxs != uint(len(b.Data.Txs)) {
  29. return errors.New("Wrong Block.Header.NumTxs")
  30. }
  31. if !bytes.Equal(b.LastBlockHash, lastBlockHash) {
  32. return errors.New("Wrong Block.Header.LastBlockHash")
  33. }
  34. if !b.LastBlockParts.Equals(lastBlockParts) {
  35. return errors.New("Wrong Block.Header.LastBlockParts")
  36. }
  37. /* TODO: Determine bounds
  38. See blockchain/reactor "stopSyncingDurationMinutes"
  39. if !b.Time.After(lastBlockTime) {
  40. return errors.New("Invalid Block.Header.Time")
  41. }
  42. */
  43. if b.Header.Height != 1 {
  44. if err := b.Validation.ValidateBasic(); err != nil {
  45. return err
  46. }
  47. }
  48. // XXX more validation
  49. return nil
  50. }
  51. // Computes and returns the block hash.
  52. // If the block is incomplete (e.g. missing Header.StateHash)
  53. // then the hash is nil, to prevent the usage of that hash.
  54. func (b *Block) Hash() []byte {
  55. if b.Header == nil || b.Validation == nil || b.Data == nil {
  56. return nil
  57. }
  58. hashHeader := b.Header.Hash()
  59. hashValidation := b.Validation.Hash()
  60. hashData := b.Data.Hash()
  61. // If hashHeader is nil, required fields are missing.
  62. if len(hashHeader) == 0 {
  63. return nil
  64. }
  65. // Merkle hash from subhashes.
  66. hashes := [][]byte{hashHeader, hashValidation, hashData}
  67. return merkle.SimpleHashFromHashes(hashes)
  68. }
  69. func (b *Block) MakePartSet() *PartSet {
  70. return NewPartSetFromData(binary.BinaryBytes(b))
  71. }
  72. // Convenience.
  73. // A nil block never hashes to anything.
  74. // Nothing hashes to a nil hash.
  75. func (b *Block) HashesTo(hash []byte) bool {
  76. if len(hash) == 0 {
  77. return false
  78. }
  79. if b == nil {
  80. return false
  81. }
  82. return bytes.Equal(b.Hash(), hash)
  83. }
  84. func (b *Block) String() string {
  85. return b.StringIndented("")
  86. }
  87. func (b *Block) StringIndented(indent string) string {
  88. if b == nil {
  89. return "nil-Block"
  90. }
  91. return fmt.Sprintf(`Block{
  92. %s %v
  93. %s %v
  94. %s %v
  95. %s}#%X`,
  96. indent, b.Header.StringIndented(indent+" "),
  97. indent, b.Validation.StringIndented(indent+" "),
  98. indent, b.Data.StringIndented(indent+" "),
  99. indent, b.Hash())
  100. }
  101. func (b *Block) StringShort() string {
  102. if b == nil {
  103. return "nil-Block"
  104. } else {
  105. return fmt.Sprintf("Block#%X", b.Hash())
  106. }
  107. }
  108. //-----------------------------------------------------------------------------
  109. type Header struct {
  110. ChainID string `json:"chain_id"`
  111. Height uint `json:"height"`
  112. Time time.Time `json:"time"`
  113. Fees uint64 `json:"fees"`
  114. NumTxs uint `json:"num_txs"`
  115. LastBlockHash []byte `json:"last_block_hash"`
  116. LastBlockParts PartSetHeader `json:"last_block_parts"`
  117. StateHash []byte `json:"state_hash"`
  118. }
  119. // NOTE: hash is nil if required fields are missing.
  120. func (h *Header) Hash() []byte {
  121. if len(h.StateHash) == 0 {
  122. return nil
  123. }
  124. buf := new(bytes.Buffer)
  125. hasher, n, err := sha256.New(), new(int64), new(error)
  126. binary.WriteBinary(h, buf, n, err)
  127. if *err != nil {
  128. panic(err)
  129. }
  130. hasher.Write(buf.Bytes())
  131. hash := hasher.Sum(nil)
  132. return hash
  133. }
  134. func (h *Header) StringIndented(indent string) string {
  135. if h == nil {
  136. return "nil-Header"
  137. }
  138. return fmt.Sprintf(`Header{
  139. %s ChainID: %v
  140. %s Height: %v
  141. %s Time: %v
  142. %s Fees: %v
  143. %s NumTxs: %v
  144. %s LastBlockHash: %X
  145. %s LastBlockParts: %v
  146. %s StateHash: %X
  147. %s}#%X`,
  148. indent, h.ChainID,
  149. indent, h.Height,
  150. indent, h.Time,
  151. indent, h.Fees,
  152. indent, h.NumTxs,
  153. indent, h.LastBlockHash,
  154. indent, h.LastBlockParts,
  155. indent, h.StateHash,
  156. indent, h.Hash())
  157. }
  158. //-----------------------------------------------------------------------------
  159. type Commit struct {
  160. Address []byte `json:"address"`
  161. Round uint `json:"round"`
  162. Signature account.SignatureEd25519 `json:"signature"`
  163. }
  164. func (commit Commit) IsZero() bool {
  165. return commit.Round == 0 && commit.Signature.IsZero()
  166. }
  167. func (commit Commit) String() string {
  168. return fmt.Sprintf("Commit{A:%X R:%v %X}", commit.Address, commit.Round, Fingerprint(commit.Signature))
  169. }
  170. //-------------------------------------
  171. // NOTE: The Commits are in order of address to preserve the bonded ValidatorSet order.
  172. // Any peer with a block can gossip commits by index with a peer without recalculating the
  173. // active ValidatorSet.
  174. type Validation struct {
  175. Commits []Commit `json:"commits"` // Commits (or nil) of all active validators in address order.
  176. // Volatile
  177. hash []byte
  178. bitArray *BitArray
  179. }
  180. func (v *Validation) ValidateBasic() error {
  181. if len(v.Commits) == 0 {
  182. return errors.New("No commits in validation")
  183. }
  184. lastAddress := []byte{}
  185. for i := 0; i < len(v.Commits); i++ {
  186. commit := v.Commits[i]
  187. if commit.IsZero() {
  188. if len(commit.Address) > 0 {
  189. return errors.New("Zero commits should not have an address")
  190. }
  191. } else {
  192. if len(commit.Address) == 0 {
  193. return errors.New("Nonzero commits should have an address")
  194. }
  195. if len(lastAddress) > 0 && bytes.Compare(lastAddress, commit.Address) != -1 {
  196. return errors.New("Invalid commit order")
  197. }
  198. lastAddress = commit.Address
  199. }
  200. }
  201. return nil
  202. }
  203. func (v *Validation) Hash() []byte {
  204. if v.hash == nil {
  205. bs := make([]interface{}, len(v.Commits))
  206. for i, commit := range v.Commits {
  207. bs[i] = commit
  208. }
  209. v.hash = merkle.SimpleHashFromBinaries(bs)
  210. }
  211. return v.hash
  212. }
  213. func (v *Validation) StringIndented(indent string) string {
  214. if v == nil {
  215. return "nil-Validation"
  216. }
  217. commitStrings := make([]string, len(v.Commits))
  218. for i, commit := range v.Commits {
  219. commitStrings[i] = commit.String()
  220. }
  221. return fmt.Sprintf(`Validation{
  222. %s %v
  223. %s}#%X`,
  224. indent, strings.Join(commitStrings, "\n"+indent+" "),
  225. indent, v.hash)
  226. }
  227. func (v *Validation) BitArray() *BitArray {
  228. if v.bitArray == nil {
  229. v.bitArray = NewBitArray(uint(len(v.Commits)))
  230. for i, commit := range v.Commits {
  231. v.bitArray.SetIndex(uint(i), !commit.IsZero())
  232. }
  233. }
  234. return v.bitArray
  235. }
  236. //-----------------------------------------------------------------------------
  237. type Data struct {
  238. Txs []Tx `json:"txs"`
  239. // Volatile
  240. hash []byte
  241. }
  242. func (data *Data) Hash() []byte {
  243. if data.hash == nil {
  244. bs := make([]interface{}, len(data.Txs))
  245. for i, tx := range data.Txs {
  246. bs[i] = account.SignBytes(config.GetString("chain_id"), tx)
  247. }
  248. data.hash = merkle.SimpleHashFromBinaries(bs)
  249. }
  250. return data.hash
  251. }
  252. func (data *Data) StringIndented(indent string) string {
  253. if data == nil {
  254. return "nil-Data"
  255. }
  256. txStrings := make([]string, len(data.Txs))
  257. for i, tx := range data.Txs {
  258. txStrings[i] = fmt.Sprintf("Tx:%v", tx)
  259. }
  260. return fmt.Sprintf(`Data{
  261. %s %v
  262. %s}#%X`,
  263. indent, strings.Join(txStrings, "\n"+indent+" "),
  264. indent, data.hash)
  265. }