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