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.

645 lines
20 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 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
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 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
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 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
9 years ago
10 years ago
10 years ago
  1. package state
  2. import (
  3. "github.com/tendermint/tendermint/account"
  4. _ "github.com/tendermint/tendermint/config/tendermint_test"
  5. "github.com/tendermint/tendermint/types"
  6. "bytes"
  7. "testing"
  8. "time"
  9. )
  10. func execTxWithState(state *State, tx types.Tx, runCall bool) error {
  11. cache := NewBlockCache(state)
  12. err := ExecTx(cache, tx, runCall, nil)
  13. if err != nil {
  14. return err
  15. } else {
  16. cache.Sync()
  17. return nil
  18. }
  19. }
  20. func execTxWithStateNewBlock(state *State, tx types.Tx, runCall bool) error {
  21. if err := execTxWithState(state, tx, runCall); err != nil {
  22. return err
  23. }
  24. state.LastBlockHeight += 1
  25. return nil
  26. }
  27. func TestCopyState(t *testing.T) {
  28. // Generate a random state
  29. s0, privAccounts, _ := RandGenesisState(10, true, 1000, 5, true, 1000)
  30. s0Hash := s0.Hash()
  31. if len(s0Hash) == 0 {
  32. t.Error("Expected state hash")
  33. }
  34. // Check hash of copy
  35. s0Copy := s0.Copy()
  36. if !bytes.Equal(s0Hash, s0Copy.Hash()) {
  37. t.Error("Expected state copy hash to be the same")
  38. }
  39. // Mutate the original; hash should change.
  40. acc0Address := privAccounts[0].PubKey.Address()
  41. acc := s0.GetAccount(acc0Address)
  42. acc.Balance += 1
  43. // The account balance shouldn't have changed yet.
  44. if s0.GetAccount(acc0Address).Balance == acc.Balance {
  45. t.Error("Account balance changed unexpectedly")
  46. }
  47. // Setting, however, should change the balance.
  48. s0.UpdateAccount(acc)
  49. if s0.GetAccount(acc0Address).Balance != acc.Balance {
  50. t.Error("Account balance wasn't set")
  51. }
  52. // Now that the state changed, the hash should change too.
  53. if bytes.Equal(s0Hash, s0.Hash()) {
  54. t.Error("Expected state hash to have changed")
  55. }
  56. // The s0Copy shouldn't have changed though.
  57. if !bytes.Equal(s0Hash, s0Copy.Hash()) {
  58. t.Error("Expected state copy hash to have not changed")
  59. }
  60. }
  61. func makeBlock(t *testing.T, state *State, validation *types.Validation, txs []types.Tx) *types.Block {
  62. if validation == nil {
  63. validation = &types.Validation{}
  64. }
  65. block := &types.Block{
  66. Header: &types.Header{
  67. ChainID: state.ChainID,
  68. Height: state.LastBlockHeight + 1,
  69. Time: state.LastBlockTime.Add(time.Minute),
  70. Fees: 0,
  71. NumTxs: len(txs),
  72. LastBlockHash: state.LastBlockHash,
  73. LastBlockParts: state.LastBlockParts,
  74. StateHash: nil,
  75. },
  76. LastValidation: validation,
  77. Data: &types.Data{
  78. Txs: txs,
  79. },
  80. }
  81. // Fill in block StateHash
  82. err := state.ComputeBlockStateHash(block)
  83. if err != nil {
  84. t.Error("Error appending initial block:", err)
  85. }
  86. if len(block.Header.StateHash) == 0 {
  87. t.Error("Expected StateHash but got nothing.")
  88. }
  89. return block
  90. }
  91. func TestGenesisSaveLoad(t *testing.T) {
  92. // Generate a state, save & load it.
  93. s0, _, _ := RandGenesisState(10, true, 1000, 5, true, 1000)
  94. // Make complete block and blockParts
  95. block := makeBlock(t, s0, nil, nil)
  96. blockParts := block.MakePartSet()
  97. // Now append the block to s0.
  98. err := ExecBlock(s0, block, blockParts.Header())
  99. if err != nil {
  100. t.Error("Error appending initial block:", err)
  101. }
  102. // Save s0
  103. s0.Save()
  104. // Sanity check s0
  105. //s0.DB.(*dbm.MemDB).Print()
  106. if s0.BondedValidators.TotalVotingPower() == 0 {
  107. t.Error("s0 BondedValidators TotalVotingPower should not be 0")
  108. }
  109. if s0.LastBlockHeight != 1 {
  110. t.Error("s0 LastBlockHeight should be 1, got", s0.LastBlockHeight)
  111. }
  112. // Load s1
  113. s1 := LoadState(s0.DB)
  114. // Compare height & blockHash
  115. if s0.LastBlockHeight != s1.LastBlockHeight {
  116. t.Error("LastBlockHeight mismatch")
  117. }
  118. if !bytes.Equal(s0.LastBlockHash, s1.LastBlockHash) {
  119. t.Error("LastBlockHash mismatch")
  120. }
  121. // Compare state merkle trees
  122. if s0.BondedValidators.Size() != s1.BondedValidators.Size() {
  123. t.Error("BondedValidators Size mismatch")
  124. }
  125. if s0.BondedValidators.TotalVotingPower() != s1.BondedValidators.TotalVotingPower() {
  126. t.Error("BondedValidators TotalVotingPower mismatch")
  127. }
  128. if !bytes.Equal(s0.BondedValidators.Hash(), s1.BondedValidators.Hash()) {
  129. t.Error("BondedValidators hash mismatch")
  130. }
  131. if s0.UnbondingValidators.Size() != s1.UnbondingValidators.Size() {
  132. t.Error("UnbondingValidators Size mismatch")
  133. }
  134. if s0.UnbondingValidators.TotalVotingPower() != s1.UnbondingValidators.TotalVotingPower() {
  135. t.Error("UnbondingValidators TotalVotingPower mismatch")
  136. }
  137. if !bytes.Equal(s0.UnbondingValidators.Hash(), s1.UnbondingValidators.Hash()) {
  138. t.Error("UnbondingValidators hash mismatch")
  139. }
  140. if !bytes.Equal(s0.accounts.Hash(), s1.accounts.Hash()) {
  141. t.Error("Accounts mismatch")
  142. }
  143. if !bytes.Equal(s0.validatorInfos.Hash(), s1.validatorInfos.Hash()) {
  144. t.Error("Accounts mismatch")
  145. }
  146. }
  147. func TestTxSequence(t *testing.T) {
  148. state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000)
  149. acc0 := state.GetAccount(privAccounts[0].PubKey.Address())
  150. acc0PubKey := privAccounts[0].PubKey
  151. acc1 := state.GetAccount(privAccounts[1].PubKey.Address())
  152. // Test a variety of sequence numbers for the tx.
  153. // The tx should only pass when i == 1.
  154. for i := -1; i < 3; i++ {
  155. sequence := acc0.Sequence + i
  156. tx := types.NewSendTx()
  157. tx.AddInputWithNonce(acc0PubKey, 1, sequence)
  158. tx.AddOutput(acc1.Address, 1)
  159. tx.Inputs[0].Signature = privAccounts[0].Sign(state.ChainID, tx)
  160. stateCopy := state.Copy()
  161. err := execTxWithState(stateCopy, tx, true)
  162. if i == 1 {
  163. // Sequence is good.
  164. if err != nil {
  165. t.Errorf("Expected good sequence to pass: %v", err)
  166. }
  167. // Check acc.Sequence.
  168. newAcc0 := stateCopy.GetAccount(acc0.Address)
  169. if newAcc0.Sequence != sequence {
  170. t.Errorf("Expected account sequence to change to %v, got %v",
  171. sequence, newAcc0.Sequence)
  172. }
  173. } else {
  174. // Sequence is bad.
  175. if err == nil {
  176. t.Errorf("Expected bad sequence to fail")
  177. }
  178. // Check acc.Sequence. (shouldn't have changed)
  179. newAcc0 := stateCopy.GetAccount(acc0.Address)
  180. if newAcc0.Sequence != acc0.Sequence {
  181. t.Errorf("Expected account sequence to not change from %v, got %v",
  182. acc0.Sequence, newAcc0.Sequence)
  183. }
  184. }
  185. }
  186. }
  187. func TestNameTxs(t *testing.T) {
  188. state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000)
  189. types.MinNameRegistrationPeriod = 5
  190. startingBlock := state.LastBlockHeight
  191. // try some bad names. these should all fail
  192. names := []string{"", "\n", "123#$%", "\x00", string([]byte{20, 40, 60, 80}), "baffledbythespectacleinallofthisyouseeehesaidwithouteyes", "no spaces please"}
  193. data := "something about all this just doesn't feel right."
  194. fee := int64(1000)
  195. numDesiredBlocks := 5
  196. for _, name := range names {
  197. amt := fee + int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
  198. tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
  199. tx.Sign(state.ChainID, privAccounts[0])
  200. if err := execTxWithState(state, tx, true); err == nil {
  201. t.Fatalf("Expected invalid name error from %s", name)
  202. }
  203. }
  204. // try some bad data. these should all fail
  205. name := "hold_it_chum"
  206. datas := []string{"cold&warm", "!@#$%^&*()", "<<<>>>>", "because why would you ever need a ~ or a & or even a % in a json file? make your case and we'll talk"}
  207. for _, data := range datas {
  208. amt := fee + int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
  209. tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
  210. tx.Sign(state.ChainID, privAccounts[0])
  211. if err := execTxWithState(state, tx, true); err == nil {
  212. t.Fatalf("Expected invalid data error from %s", data)
  213. }
  214. }
  215. validateEntry := func(t *testing.T, entry *types.NameRegEntry, name, data string, addr []byte, expires int) {
  216. if entry == nil {
  217. t.Fatalf("Could not find name %s", name)
  218. }
  219. if bytes.Compare(entry.Owner, addr) != 0 {
  220. t.Fatalf("Wrong owner. Got %X expected %X", entry.Owner, addr)
  221. }
  222. if data != entry.Data {
  223. t.Fatalf("Wrong data. Got %s expected %s", entry.Data, data)
  224. }
  225. if name != entry.Name {
  226. t.Fatalf("Wrong name. Got %s expected %s", entry.Name, name)
  227. }
  228. if expires != entry.Expires {
  229. t.Fatalf("Wrong expiry. Got %d, expected %d", entry.Expires, expires)
  230. }
  231. }
  232. // try a good one, check data, owner, expiry
  233. name = "looking_good/karaoke_bar"
  234. data = "on this side of neptune there are 1234567890 people: first is OMNIVORE. Or is it. Ok this is pretty restrictive. No exclamations :(. Faces tho :')"
  235. amt := fee + int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
  236. tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
  237. tx.Sign(state.ChainID, privAccounts[0])
  238. if err := execTxWithState(state, tx, true); err != nil {
  239. t.Fatal(err)
  240. }
  241. entry := state.GetNameRegEntry(name)
  242. validateEntry(t, entry, name, data, privAccounts[0].Address, startingBlock+numDesiredBlocks)
  243. // fail to update it as non-owner, in same block
  244. tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
  245. tx.Sign(state.ChainID, privAccounts[1])
  246. if err := execTxWithState(state, tx, true); err == nil {
  247. t.Fatal("Expected error")
  248. }
  249. // update it as owner, just to increase expiry, in same block
  250. // NOTE: we have to resend the data or it will clear it (is this what we want?)
  251. tx, _ = types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
  252. tx.Sign(state.ChainID, privAccounts[0])
  253. if err := execTxWithStateNewBlock(state, tx, true); err != nil {
  254. t.Fatal(err)
  255. }
  256. entry = state.GetNameRegEntry(name)
  257. validateEntry(t, entry, name, data, privAccounts[0].Address, startingBlock+numDesiredBlocks*2)
  258. // update it as owner, just to increase expiry, in next block
  259. tx, _ = types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
  260. tx.Sign(state.ChainID, privAccounts[0])
  261. if err := execTxWithStateNewBlock(state, tx, true); err != nil {
  262. t.Fatal(err)
  263. }
  264. entry = state.GetNameRegEntry(name)
  265. validateEntry(t, entry, name, data, privAccounts[0].Address, startingBlock+numDesiredBlocks*3)
  266. // fail to update it as non-owner
  267. state.LastBlockHeight = entry.Expires - 1
  268. tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
  269. tx.Sign(state.ChainID, privAccounts[1])
  270. if err := execTxWithState(state, tx, true); err == nil {
  271. t.Fatal("Expected error")
  272. }
  273. // once expires, non-owner succeeds
  274. state.LastBlockHeight = entry.Expires
  275. tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
  276. tx.Sign(state.ChainID, privAccounts[1])
  277. if err := execTxWithState(state, tx, true); err != nil {
  278. t.Fatal(err)
  279. }
  280. entry = state.GetNameRegEntry(name)
  281. validateEntry(t, entry, name, data, privAccounts[1].Address, state.LastBlockHeight+numDesiredBlocks)
  282. // update it as new owner, with new data (longer), but keep the expiry!
  283. data = "In the beginning there was no thing, not even the beginning. It hadn't been here, no there, nor for that matter anywhere, not especially because it had not to even exist, let alone to not. Nothing especially odd about that."
  284. oldCredit := amt - fee
  285. numDesiredBlocks = 10
  286. amt = fee + (int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data) - oldCredit)
  287. tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
  288. tx.Sign(state.ChainID, privAccounts[1])
  289. if err := execTxWithState(state, tx, true); err != nil {
  290. t.Fatal(err)
  291. }
  292. entry = state.GetNameRegEntry(name)
  293. validateEntry(t, entry, name, data, privAccounts[1].Address, state.LastBlockHeight+numDesiredBlocks)
  294. // test removal
  295. amt = fee
  296. data = ""
  297. tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
  298. tx.Sign(state.ChainID, privAccounts[1])
  299. if err := execTxWithStateNewBlock(state, tx, true); err != nil {
  300. t.Fatal(err)
  301. }
  302. entry = state.GetNameRegEntry(name)
  303. if entry != nil {
  304. t.Fatal("Expected removed entry to be nil")
  305. }
  306. // create entry by key0,
  307. // test removal by key1 after expiry
  308. name = "looking_good/karaoke_bar"
  309. data = "some data"
  310. amt = fee + int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
  311. tx, _ = types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
  312. tx.Sign(state.ChainID, privAccounts[0])
  313. if err := execTxWithState(state, tx, true); err != nil {
  314. t.Fatal(err)
  315. }
  316. entry = state.GetNameRegEntry(name)
  317. validateEntry(t, entry, name, data, privAccounts[0].Address, state.LastBlockHeight+numDesiredBlocks)
  318. state.LastBlockHeight = entry.Expires
  319. amt = fee
  320. data = ""
  321. tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
  322. tx.Sign(state.ChainID, privAccounts[1])
  323. if err := execTxWithStateNewBlock(state, tx, true); err != nil {
  324. t.Fatal(err)
  325. }
  326. entry = state.GetNameRegEntry(name)
  327. if entry != nil {
  328. t.Fatal("Expected removed entry to be nil")
  329. }
  330. }
  331. // TODO: test overflows.
  332. // TODO: test for unbonding validators.
  333. func TestTxs(t *testing.T) {
  334. state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000)
  335. //val0 := state.GetValidatorInfo(privValidators[0].Address)
  336. acc0 := state.GetAccount(privAccounts[0].PubKey.Address())
  337. acc0PubKey := privAccounts[0].PubKey
  338. acc1 := state.GetAccount(privAccounts[1].PubKey.Address())
  339. // SendTx.
  340. {
  341. state := state.Copy()
  342. tx := &types.SendTx{
  343. Inputs: []*types.TxInput{
  344. &types.TxInput{
  345. Address: acc0.Address,
  346. Amount: 1,
  347. Sequence: acc0.Sequence + 1,
  348. PubKey: acc0PubKey,
  349. },
  350. },
  351. Outputs: []*types.TxOutput{
  352. &types.TxOutput{
  353. Address: acc1.Address,
  354. Amount: 1,
  355. },
  356. },
  357. }
  358. tx.Inputs[0].Signature = privAccounts[0].Sign(state.ChainID, tx)
  359. err := execTxWithState(state, tx, true)
  360. if err != nil {
  361. t.Errorf("Got error in executing send transaction, %v", err)
  362. }
  363. newAcc0 := state.GetAccount(acc0.Address)
  364. if acc0.Balance-1 != newAcc0.Balance {
  365. t.Errorf("Unexpected newAcc0 balance. Expected %v, got %v",
  366. acc0.Balance-1, newAcc0.Balance)
  367. }
  368. newAcc1 := state.GetAccount(acc1.Address)
  369. if acc1.Balance+1 != newAcc1.Balance {
  370. t.Errorf("Unexpected newAcc1 balance. Expected %v, got %v",
  371. acc1.Balance+1, newAcc1.Balance)
  372. }
  373. }
  374. // CallTx. Just runs through it and checks the transfer. See vm, rpc tests for more
  375. {
  376. state := state.Copy()
  377. newAcc1 := state.GetAccount(acc1.Address)
  378. newAcc1.Code = []byte{0x60}
  379. state.UpdateAccount(newAcc1)
  380. tx := &types.CallTx{
  381. Input: &types.TxInput{
  382. Address: acc0.Address,
  383. Amount: 1,
  384. Sequence: acc0.Sequence + 1,
  385. PubKey: acc0PubKey,
  386. },
  387. Address: acc1.Address,
  388. GasLimit: 10,
  389. }
  390. tx.Input.Signature = privAccounts[0].Sign(state.ChainID, tx)
  391. err := execTxWithState(state, tx, true)
  392. if err != nil {
  393. t.Errorf("Got error in executing call transaction, %v", err)
  394. }
  395. newAcc0 := state.GetAccount(acc0.Address)
  396. if acc0.Balance-1 != newAcc0.Balance {
  397. t.Errorf("Unexpected newAcc0 balance. Expected %v, got %v",
  398. acc0.Balance-1, newAcc0.Balance)
  399. }
  400. newAcc1 = state.GetAccount(acc1.Address)
  401. if acc1.Balance+1 != newAcc1.Balance {
  402. t.Errorf("Unexpected newAcc1 balance. Expected %v, got %v",
  403. acc1.Balance+1, newAcc1.Balance)
  404. }
  405. }
  406. // NameTx.
  407. {
  408. entryName := "satoshi"
  409. entryData := `
  410. A purely peer-to-peer version of electronic cash would allow online
  411. payments to be sent directly from one party to another without going through a
  412. financial institution. Digital signatures provide part of the solution, but the main
  413. benefits are lost if a trusted third party is still required to prevent double-spending.
  414. We propose a solution to the double-spending problem using a peer-to-peer network.
  415. The network timestamps transactions by hashing them into an ongoing chain of
  416. hash-based proof-of-work, forming a record that cannot be changed without redoing
  417. the proof-of-work. The longest chain not only serves as proof of the sequence of
  418. events witnessed, but proof that it came from the largest pool of CPU power. As
  419. long as a majority of CPU power is controlled by nodes that are not cooperating to
  420. attack the network, they'll generate the longest chain and outpace attackers. The
  421. network itself requires minimal structure. Messages are broadcast on a best effort
  422. basis, and nodes can leave and rejoin the network at will, accepting the longest
  423. proof-of-work chain as proof of what happened while they were gone `
  424. entryAmount := int64(10000)
  425. state := state.Copy()
  426. tx := &types.NameTx{
  427. Input: &types.TxInput{
  428. Address: acc0.Address,
  429. Amount: entryAmount,
  430. Sequence: acc0.Sequence + 1,
  431. PubKey: acc0PubKey,
  432. },
  433. Name: entryName,
  434. Data: entryData,
  435. }
  436. tx.Input.Signature = privAccounts[0].Sign(state.ChainID, tx)
  437. err := execTxWithState(state, tx, true)
  438. if err != nil {
  439. t.Errorf("Got error in executing call transaction, %v", err)
  440. }
  441. newAcc0 := state.GetAccount(acc0.Address)
  442. if acc0.Balance-entryAmount != newAcc0.Balance {
  443. t.Errorf("Unexpected newAcc0 balance. Expected %v, got %v",
  444. acc0.Balance-entryAmount, newAcc0.Balance)
  445. }
  446. entry := state.GetNameRegEntry(entryName)
  447. if entry == nil {
  448. t.Errorf("Expected an entry but got nil")
  449. }
  450. if entry.Data != entryData {
  451. t.Errorf("Wrong data stored")
  452. }
  453. // test a bad string
  454. tx.Data = string([]byte{0, 1, 2, 3, 127, 128, 129, 200, 251})
  455. tx.Input.Sequence += 1
  456. tx.Input.Signature = privAccounts[0].Sign(state.ChainID, tx)
  457. err = execTxWithState(state, tx, true)
  458. if err != types.ErrTxInvalidString {
  459. t.Errorf("Expected invalid string error. Got: %s", err.Error())
  460. }
  461. }
  462. // BondTx.
  463. {
  464. state := state.Copy()
  465. tx := &types.BondTx{
  466. PubKey: acc0PubKey.(account.PubKeyEd25519),
  467. Inputs: []*types.TxInput{
  468. &types.TxInput{
  469. Address: acc0.Address,
  470. Amount: 1,
  471. Sequence: acc0.Sequence + 1,
  472. PubKey: acc0PubKey,
  473. },
  474. },
  475. UnbondTo: []*types.TxOutput{
  476. &types.TxOutput{
  477. Address: acc0.Address,
  478. Amount: 1,
  479. },
  480. },
  481. }
  482. tx.Signature = privAccounts[0].Sign(state.ChainID, tx).(account.SignatureEd25519)
  483. tx.Inputs[0].Signature = privAccounts[0].Sign(state.ChainID, tx)
  484. err := execTxWithState(state, tx, true)
  485. if err != nil {
  486. t.Errorf("Got error in executing bond transaction, %v", err)
  487. }
  488. newAcc0 := state.GetAccount(acc0.Address)
  489. if newAcc0.Balance != acc0.Balance-1 {
  490. t.Errorf("Unexpected newAcc0 balance. Expected %v, got %v",
  491. acc0.Balance-1, newAcc0.Balance)
  492. }
  493. _, acc0Val := state.BondedValidators.GetByAddress(acc0.Address)
  494. if acc0Val == nil {
  495. t.Errorf("acc0Val not present")
  496. }
  497. if acc0Val.BondHeight != state.LastBlockHeight+1 {
  498. t.Errorf("Unexpected bond height. Expected %v, got %v",
  499. state.LastBlockHeight, acc0Val.BondHeight)
  500. }
  501. if acc0Val.VotingPower != 1 {
  502. t.Errorf("Unexpected voting power. Expected %v, got %v",
  503. acc0Val.VotingPower, acc0.Balance)
  504. }
  505. if acc0Val.Accum != 0 {
  506. t.Errorf("Unexpected accum. Expected 0, got %v",
  507. acc0Val.Accum)
  508. }
  509. }
  510. // TODO UnbondTx.
  511. }
  512. func TestAddValidator(t *testing.T) {
  513. // Generate a state, save & load it.
  514. s0, privAccounts, privValidators := RandGenesisState(10, false, 1000, 1, false, 1000)
  515. // The first privAccount will become a validator
  516. acc0 := privAccounts[0]
  517. bondTx := &types.BondTx{
  518. PubKey: acc0.PubKey.(account.PubKeyEd25519),
  519. Inputs: []*types.TxInput{
  520. &types.TxInput{
  521. Address: acc0.Address,
  522. Amount: 1000,
  523. Sequence: 1,
  524. PubKey: acc0.PubKey,
  525. },
  526. },
  527. UnbondTo: []*types.TxOutput{
  528. &types.TxOutput{
  529. Address: acc0.Address,
  530. Amount: 1000,
  531. },
  532. },
  533. }
  534. bondTx.Signature = acc0.Sign(s0.ChainID, bondTx).(account.SignatureEd25519)
  535. bondTx.Inputs[0].Signature = acc0.Sign(s0.ChainID, bondTx)
  536. // Make complete block and blockParts
  537. block0 := makeBlock(t, s0, nil, []types.Tx{bondTx})
  538. block0Parts := block0.MakePartSet()
  539. // Sanity check
  540. if s0.BondedValidators.Size() != 1 {
  541. t.Error("Expected there to be 1 validators before bondTx")
  542. }
  543. // Now append the block to s0.
  544. err := ExecBlock(s0, block0, block0Parts.Header())
  545. if err != nil {
  546. t.Error("Error appending initial block:", err)
  547. }
  548. // Must save before further modification
  549. s0.Save()
  550. // Test new validator set
  551. if s0.BondedValidators.Size() != 2 {
  552. t.Error("Expected there to be 2 validators after bondTx")
  553. }
  554. // The validation for the next block should only require 1 signature
  555. // (the new validator wasn't active for block0)
  556. precommit0 := &types.Vote{
  557. Height: 1,
  558. Round: 0,
  559. Type: types.VoteTypePrecommit,
  560. BlockHash: block0.Hash(),
  561. BlockParts: block0Parts.Header(),
  562. }
  563. privValidators[0].SignVote(s0.ChainID, precommit0)
  564. block1 := makeBlock(t, s0,
  565. &types.Validation{
  566. Precommits: []*types.Vote{
  567. precommit0,
  568. },
  569. }, nil,
  570. )
  571. block1Parts := block1.MakePartSet()
  572. err = ExecBlock(s0, block1, block1Parts.Header())
  573. if err != nil {
  574. t.Error("Error appending secondary block:", err)
  575. }
  576. }