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  }