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