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.

313 lines
8.4 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
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
  1. package state
  2. import (
  3. . "github.com/tendermint/tendermint/binary"
  4. . "github.com/tendermint/tendermint/blocks"
  5. . "github.com/tendermint/tendermint/common"
  6. . "github.com/tendermint/tendermint/config"
  7. db_ "github.com/tendermint/tendermint/db"
  8. "bytes"
  9. "testing"
  10. "time"
  11. )
  12. func randAccountDetail(id uint64, status byte) (*AccountDetail, *PrivAccount) {
  13. privAccount := GenPrivAccount()
  14. privAccount.Id = id
  15. account := privAccount.Account
  16. return &AccountDetail{
  17. Account: account,
  18. Sequence: RandUInt(),
  19. Balance: RandUInt64() + 1000, // At least 1000.
  20. Status: status,
  21. }, privAccount
  22. }
  23. // The first numValidators accounts are validators.
  24. func randGenesisState(numAccounts int, numValidators int) (*State, []*PrivAccount) {
  25. db := db_.NewMemDB()
  26. accountDetails := make([]*AccountDetail, numAccounts)
  27. privAccounts := make([]*PrivAccount, numAccounts)
  28. for i := 0; i < numAccounts; i++ {
  29. if i < numValidators {
  30. accountDetails[i], privAccounts[i] =
  31. randAccountDetail(uint64(i), AccountStatusBonded)
  32. } else {
  33. accountDetails[i], privAccounts[i] =
  34. randAccountDetail(uint64(i), AccountStatusNominal)
  35. }
  36. }
  37. s0 := GenesisState(db, time.Now(), accountDetails)
  38. s0.Save()
  39. return s0, privAccounts
  40. }
  41. func TestCopyState(t *testing.T) {
  42. // Generate a state
  43. s0, _ := randGenesisState(10, 5)
  44. s0Hash := s0.Hash()
  45. if len(s0Hash) == 0 {
  46. t.Error("Expected state hash")
  47. }
  48. // Check hash of copy
  49. s0Copy := s0.Copy()
  50. if !bytes.Equal(s0Hash, s0Copy.Hash()) {
  51. t.Error("Expected state copy hash to be the same")
  52. }
  53. // Mutate the original; hash should change.
  54. accDet := s0.GetAccountDetail(0)
  55. accDet.Balance += 1
  56. // The account balance shouldn't have changed yet.
  57. if s0.GetAccountDetail(0).Balance == accDet.Balance {
  58. t.Error("Account balance changed unexpectedly")
  59. }
  60. // Setting, however, should change the balance.
  61. s0.SetAccountDetail(accDet)
  62. if s0.GetAccountDetail(0).Balance != accDet.Balance {
  63. t.Error("Account balance wasn't set")
  64. }
  65. // How that the state changed, the hash should change too.
  66. if bytes.Equal(s0Hash, s0.Hash()) {
  67. t.Error("Expected state hash to have changed")
  68. }
  69. // The s0Copy shouldn't have changed though.
  70. if !bytes.Equal(s0Hash, s0Copy.Hash()) {
  71. t.Error("Expected state copy hash to have not changed")
  72. }
  73. }
  74. func TestGenesisSaveLoad(t *testing.T) {
  75. // Generate a state, save & load it.
  76. s0, _ := randGenesisState(10, 5)
  77. // Mutate the state to append one empty block.
  78. block := &Block{
  79. Header: Header{
  80. Network: Config.Network,
  81. Height: 1,
  82. Time: s0.LastBlockTime.Add(time.Minute),
  83. Fees: 0,
  84. LastBlockHash: s0.LastBlockHash,
  85. LastBlockParts: s0.LastBlockParts,
  86. StateHash: nil,
  87. },
  88. Validation: Validation{},
  89. Data: Data{
  90. Txs: []Tx{},
  91. },
  92. }
  93. blockParts := NewPartSetFromData(BinaryBytes(block))
  94. // The second argument to AppendBlock() is false,
  95. // which sets Block.Header.StateHash.
  96. err := s0.Copy().AppendBlock(block, blockParts.Header(), false)
  97. if err != nil {
  98. t.Error("Error appending initial block:", err)
  99. }
  100. if len(block.Header.StateHash) == 0 {
  101. t.Error("Expected StateHash but got nothing.")
  102. }
  103. // Now append the block to s0.
  104. // This time we also check the StateHash (as computed above).
  105. err = s0.AppendBlock(block, blockParts.Header(), true)
  106. if err != nil {
  107. t.Error("Error appending initial block:", err)
  108. }
  109. // Save s0
  110. s0.Save()
  111. // Sanity check s0
  112. //s0.DB.(*db_.MemDB).Print()
  113. if s0.BondedValidators.TotalVotingPower() == 0 {
  114. t.Error("s0 BondedValidators TotalVotingPower should not be 0")
  115. }
  116. if s0.LastBlockHeight != 1 {
  117. t.Error("s0 LastBlockHeight should be 1, got", s0.LastBlockHeight)
  118. }
  119. // Load s1
  120. s1 := LoadState(s0.DB)
  121. // Compare height & blockHash
  122. if s0.LastBlockHeight != s1.LastBlockHeight {
  123. t.Error("LastBlockHeight mismatch")
  124. }
  125. if !bytes.Equal(s0.LastBlockHash, s1.LastBlockHash) {
  126. t.Error("LastBlockHash mismatch")
  127. }
  128. // Compare state merkle trees
  129. if s0.BondedValidators.Size() != s1.BondedValidators.Size() {
  130. t.Error("BondedValidators Size mismatch")
  131. }
  132. if s0.BondedValidators.TotalVotingPower() != s1.BondedValidators.TotalVotingPower() {
  133. t.Error("BondedValidators TotalVotingPower mismatch")
  134. }
  135. if bytes.Equal(s0.BondedValidators.Hash(), s1.BondedValidators.Hash()) {
  136. // The BondedValidators hash should have changed because
  137. // each AppendBlock() calls IncrementAccum(),
  138. // changing each validator's Accum.
  139. t.Error("BondedValidators hash should have changed")
  140. }
  141. if s0.UnbondingValidators.Size() != s1.UnbondingValidators.Size() {
  142. t.Error("UnbondingValidators Size mismatch")
  143. }
  144. if s0.UnbondingValidators.TotalVotingPower() != s1.UnbondingValidators.TotalVotingPower() {
  145. t.Error("UnbondingValidators TotalVotingPower mismatch")
  146. }
  147. if !bytes.Equal(s0.UnbondingValidators.Hash(), s1.UnbondingValidators.Hash()) {
  148. t.Error("UnbondingValidators hash mismatch")
  149. }
  150. if !bytes.Equal(s0.accountDetails.Hash(), s1.accountDetails.Hash()) {
  151. t.Error("AccountDetail mismatch")
  152. }
  153. }
  154. func TestTxSequence(t *testing.T) {
  155. state, privAccounts := randGenesisState(3, 1)
  156. acc1 := state.GetAccountDetail(1) // Non-validator
  157. // Try executing a SendTx with various sequence numbers.
  158. stxProto := SendTx{
  159. BaseTx: BaseTx{
  160. Sequence: acc1.Sequence + 1,
  161. Fee: 0},
  162. To: 2,
  163. Amount: 1,
  164. }
  165. // Test a variety of sequence numbers for the tx.
  166. // The tx should only pass when i == 1.
  167. for i := -1; i < 3; i++ {
  168. stxCopy := stxProto
  169. stx := &stxCopy
  170. stx.Sequence = uint(int(acc1.Sequence) + i)
  171. privAccounts[1].Sign(stx)
  172. stateCopy := state.Copy()
  173. err := stateCopy.ExecTx(stx)
  174. if i >= 1 {
  175. // Sequence is good.
  176. if err != nil {
  177. t.Errorf("Expected good sequence to pass")
  178. }
  179. // Check accDet.Sequence.
  180. newAcc1 := stateCopy.GetAccountDetail(1)
  181. if newAcc1.Sequence != stx.Sequence {
  182. t.Errorf("Expected account sequence to change")
  183. }
  184. } else {
  185. // Sequence is bad.
  186. if err == nil {
  187. t.Errorf("Expected bad sequence to fail")
  188. }
  189. // Check accDet.Sequence. (shouldn't have changed)
  190. newAcc1 := stateCopy.GetAccountDetail(1)
  191. if newAcc1.Sequence != acc1.Sequence {
  192. t.Errorf("Expected account sequence to not change")
  193. }
  194. }
  195. }
  196. }
  197. func TestTxs(t *testing.T) {
  198. state, privAccounts := randGenesisState(3, 1)
  199. acc0 := state.GetAccountDetail(0) // Validator
  200. acc1 := state.GetAccountDetail(1) // Non-validator
  201. acc2 := state.GetAccountDetail(2) // Non-validator
  202. // SendTx.
  203. {
  204. state := state.Copy()
  205. stx := &SendTx{
  206. BaseTx: BaseTx{
  207. Sequence: acc1.Sequence + 1,
  208. Fee: 0},
  209. To: 2,
  210. Amount: 1,
  211. }
  212. privAccounts[1].Sign(stx)
  213. err := state.ExecTx(stx)
  214. if err != nil {
  215. t.Errorf("Got error in executing send transaction, %v", err)
  216. }
  217. newAcc1 := state.GetAccountDetail(1)
  218. if acc1.Balance-1 != newAcc1.Balance {
  219. t.Errorf("Unexpected newAcc1 balance. Expected %v, got %v",
  220. acc1.Balance-1, newAcc1.Balance)
  221. }
  222. newAcc2 := state.GetAccountDetail(2)
  223. if acc2.Balance+1 != newAcc2.Balance {
  224. t.Errorf("Unexpected newAcc2 balance. Expected %v, got %v",
  225. acc2.Balance+1, newAcc2.Balance)
  226. }
  227. }
  228. // TODO: test overflows.
  229. // SendTx should fail for bonded validators.
  230. {
  231. state := state.Copy()
  232. stx := &SendTx{
  233. BaseTx: BaseTx{
  234. Sequence: acc0.Sequence + 1,
  235. Fee: 0},
  236. To: 2,
  237. Amount: 1,
  238. }
  239. privAccounts[0].Sign(stx)
  240. err := state.ExecTx(stx)
  241. if err == nil {
  242. t.Errorf("Expected error, SendTx should fail for bonded validators")
  243. }
  244. }
  245. // TODO: test for unbonding validators.
  246. // BondTx.
  247. {
  248. state := state.Copy()
  249. btx := &BondTx{
  250. BaseTx: BaseTx{
  251. Sequence: acc1.Sequence + 1,
  252. Fee: 0},
  253. }
  254. privAccounts[1].Sign(btx)
  255. err := state.ExecTx(btx)
  256. if err != nil {
  257. t.Errorf("Got error in executing bond transaction, %v", err)
  258. }
  259. newAcc1 := state.GetAccountDetail(1)
  260. if acc1.Balance != newAcc1.Balance {
  261. t.Errorf("Unexpected newAcc1 balance. Expected %v, got %v",
  262. acc1.Balance, newAcc1.Balance)
  263. }
  264. if newAcc1.Status != AccountStatusBonded {
  265. t.Errorf("Unexpected newAcc1 status.")
  266. }
  267. _, acc1Val := state.BondedValidators.GetById(acc1.Id)
  268. if acc1Val == nil {
  269. t.Errorf("acc1Val not present")
  270. }
  271. if acc1Val.BondHeight != state.LastBlockHeight {
  272. t.Errorf("Unexpected bond height. Expected %v, got %v",
  273. state.LastBlockHeight, acc1Val.BondHeight)
  274. }
  275. if acc1Val.VotingPower != acc1.Balance {
  276. t.Errorf("Unexpected voting power. Expected %v, got %v",
  277. acc1Val.VotingPower, acc1.Balance)
  278. }
  279. if acc1Val.Accum != 0 {
  280. t.Errorf("Unexpected accum. Expected 0, got %v",
  281. acc1Val.Accum)
  282. }
  283. }
  284. // TODO UnbondTx.
  285. // TODO NameTx.
  286. }