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.

263 lines
8.4KB

  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 globals
  17. import "os"
  18. import "fmt"
  19. import "math"
  20. import "net/url"
  21. import "strings"
  22. import "strconv"
  23. import "math/big"
  24. import "path/filepath"
  25. import "golang.org/x/net/proxy"
  26. import "github.com/sirupsen/logrus"
  27. import log "github.com/sirupsen/logrus"
  28. import "github.com/deroproject/derosuite/config"
  29. import "github.com/deroproject/derosuite/address"
  30. type ChainState int // block chain can only be in 2 state, either SYNCRONISED or syncing
  31. const (
  32. SYNCRONISED ChainState = iota // 0
  33. SYNCING // 1
  34. )
  35. // all the the global variables used by the program are stored here
  36. // since the entire logic is designed around a state machine driven by external events
  37. // once the core starts nothing changes until there is a network state change
  38. var Incoming_Block = make([]byte, 100) // P2P feeds it, blockchain consumes it
  39. var Outgoing_Block = make([]byte, 100) // blockchain feeds it, P2P consumes it only if a block has been mined
  40. var Incoming_Tx = make([]byte, 100) // P2P feeds it, blockchain consumes it
  41. var Outgoing_Tx = make([]byte, 100) // blockchain feeds it, P2P consumes it only if a user has created a Tx mined
  42. var Subsystem_Active uint32 // atomic counter to show how many subsystems are active
  43. var Exit_In_Progress bool
  44. // on init this variable is updated to setup global config in 1 go
  45. var Config config.CHAIN_CONFIG
  46. // global logger all components will use it with context
  47. var Logger *logrus.Logger
  48. var Log_Level = logrus.InfoLevel // default is info level
  49. var ilog_formatter *logrus.TextFormatter // used while tracing code
  50. var Dialer proxy.Dialer = proxy.Direct // for proxy and direct connections
  51. // all outgoing connections , including DNS requests must be made using this
  52. // all program arguments are available here
  53. var Arguments map[string]interface{}
  54. func Initialize() {
  55. var err error
  56. _ = err
  57. Config = config.Mainnet // default is mainnnet
  58. if Arguments["--testnet"].(bool) == true { // setup testnet if requested
  59. Config = config.Testnet
  60. }
  61. // formatter := &logrus.TextFormatter{DisableColors : true}
  62. //Logger= &logrus.Logger{Formatter:formatter}
  63. Logger = logrus.New()
  64. //Logger.Formatter = &logrus.TextFormatter{DisableColors : true}
  65. Logger.SetLevel(logrus.InfoLevel)
  66. if Arguments["--debug"].(bool) == true { // setup debug mode if requested
  67. Log_Level = logrus.DebugLevel
  68. Logger.SetLevel(logrus.DebugLevel)
  69. }
  70. Logger.AddHook(&HOOK) // add rlog hook
  71. // choose socks based proxy if user requested so
  72. if Arguments["--socks-proxy"] != nil {
  73. log.Debugf("Setting up proxy using %s", Arguments["--socks-proxy"].(string))
  74. //uri, err := url.Parse("socks5://127.0.0.1:9000") // "socks5://demo:demo@192.168.99.100:1080"
  75. uri, err := url.Parse("socks5://" + Arguments["--socks-proxy"].(string)) // "socks5://demo:demo@192.168.99.100:1080"
  76. if err != nil {
  77. log.Fatalf("Error parsing socks proxy: err %s", err)
  78. }
  79. Dialer, err = proxy.FromURL(uri, proxy.Direct)
  80. if err != nil {
  81. log.Fatalf("Error creating socks proxy: err \"%s\" from data %s ", err, Arguments["--socks-proxy"].(string))
  82. }
  83. }
  84. // windows and logrus have issues while printing colored messages, so disable them right now
  85. ilog_formatter = &logrus.TextFormatter{} // this needs to be created after after top logger has been intialised
  86. ilog_formatter.DisableColors = true
  87. ilog_formatter.DisableTimestamp = true
  88. // lets create data directories
  89. err = os.MkdirAll(GetDataDirectory(), 0750)
  90. if err != nil {
  91. fmt.Printf("Error creating/accessing directory %s , err %s\n", GetDataDirectory(), err)
  92. }
  93. }
  94. // tells whether we are in mainnet mode
  95. // if we are not mainnet, we are a testnet,
  96. // we will only have a single mainnet ,( but we may have one or more testnets )
  97. func IsMainnet() bool {
  98. if Config.Name == "mainnet" {
  99. return true
  100. }
  101. return false
  102. }
  103. // return different directories for different networks ( mainly mainnet, testnet, simulation )
  104. // this function is specifically for daemon
  105. func GetDataDirectory() string {
  106. data_directory, err := os.Getwd()
  107. if err != nil {
  108. fmt.Printf("Error obtaining current directory, using temp dir err %s\n", err)
  109. data_directory = os.TempDir()
  110. }
  111. // if user provided an option, override default
  112. if Arguments["--data-dir"] != nil {
  113. data_directory = Arguments["--data-dir"].(string)
  114. }
  115. if IsMainnet() {
  116. return filepath.Join(data_directory, "mainnet")
  117. }
  118. return filepath.Join(data_directory, "testnet")
  119. }
  120. /* this function converts a logrus entry into a txt formater based entry with no colors for tracing*/
  121. func CTXString(entry *logrus.Entry) string {
  122. entry.Level = logrus.DebugLevel
  123. data, _ := ilog_formatter.Format(entry)
  124. return string(data)
  125. }
  126. // never do any division operation on money due to floating point issues
  127. // newbies, see type the next in python interpretor "3.33-3.13"
  128. //
  129. func FormatMoney(amount uint64) string {
  130. return FormatMoneyPrecision(amount, 8) // default is 8 precision after floating point
  131. }
  132. // 0
  133. func FormatMoney0(amount uint64) string {
  134. return FormatMoneyPrecision(amount, 0)
  135. }
  136. //8 precision
  137. func FormatMoney8(amount uint64) string {
  138. return FormatMoneyPrecision(amount, 8)
  139. }
  140. // 12 precision
  141. func FormatMoney12(amount uint64) string {
  142. return FormatMoneyPrecision(amount, 12) // default is 8 precision after floating point
  143. }
  144. // format money with specific precision
  145. func FormatMoneyPrecision(amount uint64, precision int) string {
  146. hard_coded_decimals := new(big.Float).SetInt64(1000000000000)
  147. float_amount, _, _ := big.ParseFloat(fmt.Sprintf("%d", amount), 10, 0, big.ToZero)
  148. result := new(big.Float)
  149. result.Quo(float_amount, hard_coded_decimals)
  150. return result.Text('f', precision) // 8 is display precision after floating point
  151. }
  152. // this will parse and validate an address, in reference to the current main/test mode
  153. func ParseValidateAddress(str string) (addr *address.Address, err error) {
  154. addr, err = address.NewAddress(strings.TrimSpace(str))
  155. if err != nil {
  156. return
  157. }
  158. // check whether the domain is valid
  159. if !addr.IsDERONetwork() {
  160. err = fmt.Errorf("Invalid DERO address")
  161. return
  162. }
  163. if IsMainnet() != addr.IsMainnet() {
  164. if IsMainnet() {
  165. err = fmt.Errorf("Address belongs to DERO testnet and is invalid")
  166. } else {
  167. err = fmt.Errorf("Address belongs to DERO mainnet and is invalid")
  168. }
  169. return
  170. }
  171. return
  172. }
  173. // this will covert an amount in string form to atomic units
  174. func ParseAmount(str string) (amount uint64, err error) {
  175. float_amount, base, err := big.ParseFloat(strings.TrimSpace(str), 10, 0, big.ToZero)
  176. if err != nil {
  177. err = fmt.Errorf("Amount could not be parsed err: %s", err)
  178. return
  179. }
  180. if base != 10 {
  181. err = fmt.Errorf("Amount should be in base 10 (0123456789)")
  182. return
  183. }
  184. if float_amount.Cmp(new(big.Float).Abs(float_amount)) != 0 { // number and abs(num) not equal means number is neg
  185. err = fmt.Errorf("Amount cannot be negative")
  186. return
  187. }
  188. // multiply by 12 zeroes
  189. hard_coded_decimals := new(big.Float).SetInt64(1000000000000)
  190. float_amount.Mul(float_amount, hard_coded_decimals)
  191. /*if !float_amount.IsInt() {
  192. err = fmt.Errorf("Amount is invalid %s ", float_amount.Text('f',0))
  193. return
  194. }*/
  195. // convert amount to uint64
  196. //amount, _ = float_amount.Uint64() // sanity checks again
  197. amount, err = strconv.ParseUint(float_amount.Text('f', 0), 10, 64)
  198. if err != nil {
  199. err = fmt.Errorf("Amount is invalid %s ", float_amount.Text('f', 0))
  200. return
  201. }
  202. if amount == 0 {
  203. err = fmt.Errorf("0 cannot be transferred")
  204. return
  205. }
  206. if amount == math.MaxUint64 {
  207. err = fmt.Errorf("Amount is invalid")
  208. return
  209. }
  210. return // return the number
  211. }