Dero Web Wallet derosuite. This repo contains changes required for webwallet. With this changes any Dero daemon can become web wallet. All changes are related to daemon rpc server and wallet to make it light and faster.
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.

290 lines
9.5KB

  1. // Copyright 2017-2018 DERO Project. All rights reserved.
  2. // Use of this source code in any form is governed by RESEARCH license.
  3. // license can be found in the LICENSE file.
  4. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
  5. //
  6. //
  7. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  8. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  10. // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  14. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. package simulator
  17. import "os"
  18. import "fmt"
  19. import "time"
  20. import "bufio"
  21. import "testing"
  22. import "path/filepath"
  23. import "github.com/romana/rlog"
  24. //import "encoding/hex"
  25. import "github.com/deroproject/derosuite/config"
  26. import "github.com/deroproject/derosuite/globals"
  27. import "github.com/deroproject/derosuite/crypto"
  28. import "github.com/deroproject/derosuite/blockchain"
  29. import "github.com/deroproject/derosuite/address"
  30. import "github.com/deroproject/derosuite/walletapi"
  31. //import "github.com/deroproject/derosuite/blockchain"
  32. // testing basic functionality of wallet in case of chain forks
  33. // mem pool okay etc
  34. func Test_Chain_Fork_Test(t *testing.T) {
  35. // start the simulator ( mine genesis block )
  36. sim, _ := Init_Simulator(config.Testnet)
  37. defer sim.Stop()
  38. // create 3 wallets, w1,w2,w3
  39. temp_db := filepath.Join(os.TempDir(), "test_w1.db")
  40. os.Remove(temp_db)
  41. w1, err := walletapi.Create_Encrypted_Wallet(temp_db, "QWER", *crypto.RandomScalar())
  42. if err != nil {
  43. t.Fatalf("Cannot create encrypted wallet, err %s", err)
  44. }
  45. temp_db = filepath.Join(os.TempDir(), "test_w2.db")
  46. os.Remove(temp_db)
  47. w2, err := walletapi.Create_Encrypted_Wallet(temp_db, "QWER", *crypto.RandomScalar())
  48. if err != nil {
  49. t.Fatalf("Cannot create encrypted wallet, err %s", err)
  50. }
  51. temp_db = filepath.Join(os.TempDir(), "test_w3.db")
  52. os.Remove(temp_db)
  53. w3, err := walletapi.Create_Encrypted_Wallet(temp_db, "QWER", *crypto.RandomScalar())
  54. if err != nil {
  55. t.Fatalf("Cannot create encrypted wallet, err %s", err)
  56. }
  57. // first chain splits into 2 parts
  58. _ = w2
  59. _ = w3
  60. // mine the first block and get reward
  61. // w1 wallet has 5 rewards
  62. for i := 0; i < 10; i++ {
  63. sim.Mine_New_Block_Address(w1.GetAddress())
  64. sim.Mine_New_Block_Address(w2.GetAddress())
  65. }
  66. //sim.Mine_New_Block_Address(w2.GetAddress())
  67. //sim.Mine_New_Block_Address(w3.GetAddress())
  68. //t.Logf("Chain height %d", sim.Chain.Get_Height())
  69. for i := 0; i < 60; i++ {
  70. sim.Mine_New_Block() // add a random block to random miner
  71. }
  72. // lets do a transaction now
  73. w1.Sync_Wallet_With_Daemon()
  74. tx, _, _, _, err := w1.Transfer([]address.Address{w3.GetAddress()}, []uint64{1000}, 0, "", 25037535000, 0)
  75. if err != nil {
  76. t.Fatalf("Error creating transaction err %s", err)
  77. }
  78. if !sim.Chain.Mempool.Mempool_Add_TX(tx, 0) {
  79. t.Fatalf("Add TX to pool failed ")
  80. }
  81. sim.Chain.Mempool.Mempool_Print()
  82. sim.Mine_New_Block()
  83. first_mined_block := sim.Chain.Get_Top_ID()
  84. for i := 0; i < 4; i++ {
  85. sim.Mine_New_Block() // add a random block to random miner
  86. }
  87. first_top := sim.Chain.Get_Top_ID()
  88. // now lets fork the chain, before the TX was mined
  89. pre_fork_top := sim.Chain.Get_Top_ID() // get top id before forking
  90. // start a fork with 30 blocks at suitable height
  91. block_hash, _ := sim.Chain.Load_BL_ID_at_Height(sim.Chain.Get_Height() - 8) // fork starts at this block
  92. for {
  93. cbl, _ := sim.Chain.Create_new_miner_block(block_hash, w1.GetAddress(), 0) // create a new block with
  94. sim.Chain.Add_Complete_Block(cbl) // add the block to alt-chain, at some point, alt-chain will become main chain
  95. block_hash = cbl.Bl.GetHash()
  96. if pre_fork_top != sim.Chain.Get_Top_ID() { // if the chain has flipped, check the balances
  97. rlog.Infof("Chain has forked")
  98. break
  99. }
  100. }
  101. // the tx must be orphan at this point
  102. if !sim.Chain.Is_TX_Orphan(tx.GetHash()) {
  103. t.Fatalf("TX must be orphan but it is not")
  104. }
  105. sim.Mine_New_Block() // add a random block to random miner, this will mine popped tx
  106. if sim.Chain.Is_TX_Orphan(tx.GetHash()) {
  107. t.Fatalf("TX must NOT be orphan but it is still orphan")
  108. }
  109. second_mined_block := sim.Chain.Get_Top_ID()
  110. // lets fork the current chain 2 blocks back
  111. second_fork_top := sim.Chain.Get_Top_ID() // get top id before forking
  112. // start a fork with 30 blocks at suitable height
  113. block_hash, _ = sim.Chain.Load_BL_ID_at_Height(sim.Chain.Get_Height() - 4) // fork starts at this block
  114. for {
  115. cbl, _ := sim.Chain.Create_new_miner_block(block_hash, w1.GetAddress(), 0) // create a new block with
  116. sim.Chain.Add_Complete_Block(cbl) // add the block to alt-chain, at some point, alt-chain will become main chain
  117. block_hash = cbl.Bl.GetHash()
  118. if second_fork_top != sim.Chain.Get_Top_ID() { // if the chain has flipped, check the balances
  119. rlog.Infof("Chain has forked")
  120. break
  121. }
  122. }
  123. // the tx will now move to another alt chain
  124. sim.Mine_New_Block() // add a random block to random miner, this will mine popped tx
  125. third_mined_block := sim.Chain.Get_Top_ID()
  126. rlog.Infof("TX %s mined in block FIRST %s firsttop %s", tx.GetHash(), first_mined_block, first_top)
  127. rlog.Infof("TX %s mined in block SECOND %s", tx.GetHash(), second_mined_block)
  128. rlog.Infof("TX %s mined in block THIRD %s", tx.GetHash(), third_mined_block)
  129. // letss jump back to original chain
  130. //block_hash, _ = sim.Chain.Load_BL_ID_at_Height(first_mined_block) // fork starts at this block
  131. block_hash = first_top
  132. for {
  133. cbl, _ := sim.Chain.Create_new_miner_block(block_hash, w1.GetAddress(), 0) // create a new block with
  134. sim.Chain.Add_Complete_Block(cbl) // add the block to alt-chain, at some point, alt-chain will become main chain
  135. block_hash = cbl.Bl.GetHash()
  136. if third_mined_block != sim.Chain.Get_Top_ID() { // if the chain has flipped, check the balances
  137. rlog.Infof("Chain has forked, we should be at the top block")
  138. break
  139. }
  140. }
  141. first_top = sim.Chain.Get_Top_ID()
  142. WriteBlockChainTree(sim.Chain, "/tmp/sim.dot")
  143. if !sim.Chain.Is_Block_Orphan(third_mined_block) {
  144. t.Fatalf("Third block should be marked orphan !!! but is NOT")
  145. }
  146. if !sim.Chain.Is_Block_Orphan(second_mined_block) {
  147. t.Fatalf("Second block should be marked orphan !!! but is NOT")
  148. }
  149. if sim.Chain.Is_Block_Orphan(first_mined_block) {
  150. t.Fatalf("First block should NOT be marked orphan !!! but it is orphan")
  151. }
  152. if sim.Chain.Is_TX_Orphan(tx.GetHash()) {
  153. t.Fatalf("TX is marked orphan, it should actually be no longer orphan")
  154. }
  155. sim.Chain.Mempool.Mempool_Print()
  156. // lets jump back to Alt-Alt Chain
  157. block_hash = second_mined_block
  158. for {
  159. cbl, _ := sim.Chain.Create_new_miner_block(block_hash, w1.GetAddress(), 0) // create a new block with
  160. sim.Chain.Add_Complete_Block(cbl) // add the block to alt-chain, at some point, alt-chain will become main chain
  161. block_hash = cbl.Bl.GetHash()
  162. if first_top != sim.Chain.Get_Top_ID() { // if the chain has flipped, check the balances
  163. rlog.Infof("Chain has forked, we should be at the top block")
  164. break
  165. }
  166. }
  167. WriteBlockChainTree(sim.Chain, "/tmp/sim2.dot")
  168. if !sim.Chain.Is_Block_Orphan(first_mined_block) {
  169. t.Fatalf("First block should be marked orphan !!! but it is NOT orphan")
  170. }
  171. if sim.Chain.Is_Block_Orphan(second_mined_block) {
  172. t.Fatalf("Second block should NOT be marked orphan !!! but is ")
  173. }
  174. if !sim.Chain.Is_Block_Orphan(third_mined_block) {
  175. t.Fatalf("Third block should be marked orphan !!! but is NOT")
  176. }
  177. if sim.Chain.Is_TX_Orphan(tx.GetHash()) {
  178. t.Fatalf("TX is marked orphan, it should actually be no longer orphan")
  179. }
  180. time.Sleep(1 * time.Second)
  181. }
  182. func writenode(chain *blockchain.Blockchain, w *bufio.Writer, blid crypto.Hash, chain_name string) { // process a node, recursively
  183. children := chain.Load_Block_Children(blid)
  184. block_name := blid.String() // embed TX
  185. // orphan = ""
  186. if chain.Is_Block_Orphan(blid) {
  187. block_name = "ORPHAN" + `\n` + block_name
  188. }
  189. bl, _ := chain.Load_BL_FROM_ID(blid)
  190. for j := range bl.Tx_hashes {
  191. block_name = block_name + `\n` + bl.Tx_hashes[j].String()
  192. }
  193. //test [label="line 1\nline 2"]
  194. w.WriteString(fmt.Sprintf("L%s [label = \"%s\"]\n", blid.String(), block_name))
  195. for i := range children {
  196. cdiff := chain.Load_Block_Cumulative_Difficulty(children[i])
  197. connected_how := chain_name + " main"
  198. if i != 0 {
  199. connected_how = chain_name + " alt"
  200. }
  201. if len(children) >= 1 {
  202. w.WriteString(fmt.Sprintf("L%s -> L%s [ label = \"%s %d height %d %d\" ];\n", blid.String(), children[i].String(), connected_how, cdiff, chain.Load_Height_for_BL_ID(children[i]), i))
  203. }
  204. if len(children) == 1 {
  205. writenode(chain, w, children[i], chain_name)
  206. } else {
  207. writenode(chain, w, children[i], connected_how)
  208. }
  209. }
  210. }
  211. func WriteBlockChainTree(chain *blockchain.Blockchain, filename string) (err error) {
  212. f, err := os.Create(filename)
  213. if err != nil {
  214. return
  215. }
  216. defer f.Close()
  217. w := bufio.NewWriter(f)
  218. defer w.Flush()
  219. w.WriteString("digraph dero_blockchain_graph { \n")
  220. writenode(chain, w, globals.Config.Genesis_Block_Hash, "")
  221. w.WriteString("}\n")
  222. return
  223. }