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.

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