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.

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