<commit_before>package core

import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/dghubble/sling"
	"github.com/kristjank/ark-go/arkcoin"
)

//ArkNetworkType for network switching
type ArkNetworkType int

const (
	//MAINNET connection
	MAINNET = iota
	//DEVNET connection
	DEVNET
	//KAPU
	KAPU
	//KAPUDEVNET
	KAPUDEVNET
)

//TO HELP DIVIDE
//TODO rename
const (
	SATOSHI = 100000000
)

//EnvironmentParams - Global ARK EnvironmentParams read from acitve peers
var EnvironmentParams = new(ArkEnvParams)

//ArkEnvParams structure to hold parameters from autoconfigure
//structure is filled from peers at arkclient init call
type ArkEnvParams struct {
	Success bool    `json:"success"`
	Network Network `json:"network"`
	Fees    Fees    `json:"fees"`
}

//Fees constant parameters for active configuration
type Fees struct {
	Send            int64 `json:"send"`
	Vote            int64 `json:"vote"`
	SecondSignature int64 `json:"secondsignature"`
	Delegate        int64 `json:"delegate"`
	MultiSignature  int64 `json:"multisignature"`
}

//Network parameters
type Network struct {
	Nethash        string         `json:"nethash"`
	Token          string         `json:"token"`
	Symbol         string         `json:"symbol"`
	Explorer       string         `json:"explorer"`
	AddressVersion byte           `json:"version"` //this is address generator version!!!
	Type           ArkNetworkType //holding ark networktype
	ActivePeer     Peer
	PeerList       []Peer
}

//LoadActiveConfiguration reads arknetwork parameters from the Network
//and fills the EnvironmentParams structure
//selected and connected peer address is returned
func LoadActiveConfiguration(arknetwork ArkNetworkType) string {
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)

	selectedPeer := ""
	EnvironmentParams.Network.Type = arknetwork
	//looping peers comunication until we get autoconfigure response
	i := 0
	for selectedPeer == "" && i < 10 {

		i++
		switch arknetwork {
		case MAINNET:
			log.Println("Active network is ARK MAINNET")
			selectedPeer = seedList[r1.Intn(len(seedList))]
			log.Println("Random peer selected: ", selectedPeer)

		case DEVNET:
			log.Println("Active network is ARK DEVNET")
			selectedPeer = testSeedList[r1.Intn(len(testSeedList))]
			log.Println("Random peer selected: ", selectedPeer)
		case KAPU:
			log.Println("Active network is KAPU MAINNET")
			selectedPeer = seedListKAPU[r1.Intn(len(seedListKAPU))]
			log.Println("Random peer selected: ", selectedPeer)

		}
		log.Println("Connecting to random peer", selectedPeer, r1.Intn(len(seedList)))
		//reading basic network params
		res, err := http.Get("http://" + selectedPeer + "/api/loader/autoconfigure")
		if err != nil {
			log.Println("Error receiving autoloader params rest from: ", selectedPeer, " Error: ", err.Error())
			selectedPeer = ""
		} else {
			json.NewDecoder(res.Body).Decode(&EnvironmentParams)
		}
	}

	if selectedPeer == "" {
		log.Fatal("Unable to connect to blockchain, exiting")
	}

	//reading fees
	res, err := http.Get("http://" + selectedPeer + "/api/blocks/getfees")
	if err != nil {
		log.Fatal("Error receiving fees params rest from: ", selectedPeer)
	}
	json.NewDecoder(res.Body).Decode(&EnvironmentParams)

	//getting connected peer params from peer
	peerParams := strings.Split(selectedPeer, ":")
	peerRes := new(PeerResponse)
	res, err = http.Get("http://" + selectedPeer + "/api/peers/get/?ip=" + peerParams[0] + "&port=" + peerParams[1])
	if err != nil {
		log.Fatal("Error receiving peer status from: ", selectedPeer, err.Error(), res.StatusCode)
	}
	json.NewDecoder(res.Body).Decode(peerRes)
	//saving peer parameters to globals
	EnvironmentParams.Network.ActivePeer = peerRes.SinglePeer

	return "http://" + optimizePeerList(selectedPeer)
}

func optimizePeerList(selectedPeer string) string {
	tmpClient := &ArkClient{
		sling: sling.New().Client(nil).Base("http://"+selectedPeer).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}

	peerResp, err, _ := tmpClient.GetAllPeers()
	if err.ErrorObj != nil {
		log.Println("Error getting peer list")
		return selectedPeer
	}

	EnvironmentParams.Network.PeerList = peerResp.Peers
	log.Println("Start to optimize peer list, currently ", len(EnvironmentParams.Network.PeerList), " peers.")

	//setting the version condition
	//TODO - bring from settings as param
	versionString := "1.0.1"
	if EnvironmentParams.Network.Type == DEVNET {
		versionString = "1.1.1"
	} else if EnvironmentParams.Network.Type == KAPU {
		versionString = "0.3.0"
	}

	//Clean the peer list (filters not working as they shoud) - so checking again here
	maxHeight := EnvironmentParams.Network.ActivePeer.Height
	for i := len(EnvironmentParams.Network.PeerList) - 1; i >= 0; i-- {
		peer := EnvironmentParams.Network.PeerList[i]

		// Condition to decide if current element has to be deleted:
		if peer.Status != "OK" || peer.Port != EnvironmentParams.Network.ActivePeer.Port || peer.Version != versionString {
			EnvironmentParams.Network.PeerList = append(EnvironmentParams.Network.PeerList[:i], EnvironmentParams.Network.PeerList[i+1:]...)
			//log.Println("Removing peer", peer.IP, peer.Status, peer.Height)
			continue
		}
		//if all is ok and height is higher - we preffer peers with higher hight
		if peer.Height > maxHeight {
			log.Println("Setting new active peer, found OK peer with bigger block height", peer.Height, maxHeight)
			EnvironmentParams.Network.ActivePeer = peer
			selectedPeer = fmt.Sprintf("%s:%d", peer.IP, peer.Port)
			maxHeight = peer.Height
		}
	}

	//removing peers with difference more then 17 blocks, that is 10x8s behing mainheight
	for i := len(EnvironmentParams.Network.PeerList) - 1; i >= 0; i-- {
		peer := EnvironmentParams.Network.PeerList[i]

		if maxHeight-peer.Height > 17 {
			EnvironmentParams.Network.PeerList = append(EnvironmentParams.Network.PeerList[:i], EnvironmentParams.Network.PeerList[i+1:]...)
			//log.Println("Removing peer, based on maxheight difference condition", peer.IP, peer.Status, peer.Height)
			continue
		}
	}
	log.Println("End of peer optimization, remaining ", len(EnvironmentParams.Network.PeerList), " peers.")
	return selectedPeer
}

func switchNetwork(arkNetwork ArkNetworkType) {
	BaseURL = LoadActiveConfiguration(arkNetwork)
	var wifHeader = []byte{170}

	if arkNetwork == DEVNET {
		wifHeader = []byte{239}
	}

	coinParams := arkcoin.Params{
		AddressHeader:          EnvironmentParams.Network.AddressVersion,
		DumpedPrivateKeyHeader: wifHeader,
	}
	arkcoin.SetActiveCoinConfiguration(&coinParams)
}

//SetActiveConfiguration sets a new client connection, switches network and reads network settings from peer
//usage - must reassing new pointer value: arkapi = arkapi.SetActiveConfiguration(MAINNET)
func (s *ArkClient) SetActiveConfiguration(arkNetwork ArkNetworkType) *ArkClient {
	switchNetwork(arkNetwork)
	return NewArkClient(nil)
}

var seedList = [...]string{
	"172.16.17.32:4001",
	"192.168.127.12:4001",
	"192.168.3.11:4001",
	"172.16.17.32:4001",
	"192.168.3.11:4001",
	"192.168.3.11:4001",
	"192.168.127.12:4001",
	"192.168.127.12:4001",
	"192.168.127.12:4001",
	"172.16.58.3:4001",
	"192.168.127.12:4001",
	"172.16.58.3:4001",
	"172.16.17.32:4001",
	"172.16.31.10:4001",
	"172.16.17.32:4001"}

var testSeedList = [...]string{
	"172.16.17.32:4002",
	"172.16.58.3:4002",
	"192.168.3.11:4002",
	"192.168.127.12:4002",
	"172.16.58.3:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"192.168.3.11:4002",
	"192.168.127.12:4002",
	"172.16.58.3:4002",
	"192.168.3.11:4002",
	"192.168.3.11:4002",
	"172.16.31.10:4002",
	"172.16.17.32:4002",
	"192.168.127.12:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"192.168.3.11:4002",
	"172.16.31.10:4002",
	"172.16.58.3:4002",
	"172.16.17.32:4002",
	"192.168.3.11:4002",
	"172.16.58.3:4002",
	"172.16.17.32:4002",
	"192.168.3.11:4002",
	"192.168.3.11:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"172.16.58.3:4002",
	"172.16.31.10:4002",
	"172.16.58.3:4002",
	"192.168.127.12:4002",
	"192.168.127.12:4002",
	"192.168.3.11:4002",
	"172.16.58.3:4002",
	"192.168.127.12:4002",
	"172.16.17.32:4002",
	"192.168.3.11:4002",
	"172.16.58.3:4002",
	"172.16.31.10:4002",
	"172.16.58.3:4002",
	"192.168.3.11:4002",
	"192.168.127.12:4002",
	"172.16.17.32:4002",
	"172.16.17.32:4002",
	"172.16.58.3:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"192.168.3.11:4002",
	"172.16.31.10:4002"}

var seedListKAPU = [...]string{
	"172.16.31.10:4600",
	"172.16.31.10:4600",
	"172.16.31.10:4600",
	"192.168.127.12:4600",
	"192.168.3.11:4600",
	"192.168.3.11:4600",
	"172.16.58.3:4600",
	"192.168.127.12:4600",
	"172.16.58.3:4600",
	"192.168.3.11:9700",
	"192.168.3.11:4600",
	"172.16.17.32:4600",
	"172.16.17.32:4600",
	"192.168.3.11:4600",
	"172.16.17.32:4600",
	"172.16.17.32:4600",
	"172.16.17.32:4600",
	"172.16.31.10:4600",
	"192.168.127.12:4600"}
<commit_msg>devnet and mainet updates to latest core update adjustment<commit_after>package core

import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/dghubble/sling"
	"github.com/kristjank/ark-go/arkcoin"
)

//ArkNetworkType for network switching
type ArkNetworkType int

const (
	//MAINNET connection
	MAINNET = iota
	//DEVNET connection
	DEVNET
	//KAPU
	KAPU
	//KAPUDEVNET
	KAPUDEVNET
)

//TO HELP DIVIDE
//TODO rename
const (
	SATOSHI = 100000000
)

//EnvironmentParams - Global ARK EnvironmentParams read from acitve peers
var EnvironmentParams = new(ArkEnvParams)

//ArkEnvParams structure to hold parameters from autoconfigure
//structure is filled from peers at arkclient init call
type ArkEnvParams struct {
	Success bool    `json:"success"`
	Network Network `json:"network"`
	Fees    Fees    `json:"fees"`
}

//Fees constant parameters for active configuration
type Fees struct {
	Send            int64 `json:"send"`
	Vote            int64 `json:"vote"`
	SecondSignature int64 `json:"secondsignature"`
	Delegate        int64 `json:"delegate"`
	MultiSignature  int64 `json:"multisignature"`
}

//Network parameters
type Network struct {
	Nethash        string         `json:"nethash"`
	Token          string         `json:"token"`
	Symbol         string         `json:"symbol"`
	Explorer       string         `json:"explorer"`
	AddressVersion byte           `json:"version"` //this is address generator version!!!
	Type           ArkNetworkType //holding ark networktype
	ActivePeer     Peer
	PeerList       []Peer
}

//LoadActiveConfiguration reads arknetwork parameters from the Network
//and fills the EnvironmentParams structure
//selected and connected peer address is returned
func LoadActiveConfiguration(arknetwork ArkNetworkType) string {
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)

	selectedPeer := ""
	EnvironmentParams.Network.Type = arknetwork
	//looping peers comunication until we get autoconfigure response
	i := 0
	for selectedPeer == "" && i < 10 {

		i++
		switch arknetwork {
		case MAINNET:
			log.Println("Active network is ARK MAINNET")
			selectedPeer = seedList[r1.Intn(len(seedList))]
			log.Println("Random peer selected: ", selectedPeer)

		case DEVNET:
			log.Println("Active network is ARK DEVNET")
			selectedPeer = testSeedList[r1.Intn(len(testSeedList))]
			log.Println("Random peer selected: ", selectedPeer)
		case KAPU:
			log.Println("Active network is KAPU MAINNET")
			selectedPeer = seedListKAPU[r1.Intn(len(seedListKAPU))]
			log.Println("Random peer selected: ", selectedPeer)

		}
		log.Println("Connecting to random peer", selectedPeer, r1.Intn(len(seedList)))
		//reading basic network params
		res, err := http.Get("http://" + selectedPeer + "/api/loader/autoconfigure")
		if err != nil {
			log.Println("Error receiving autoloader params rest from: ", selectedPeer, " Error: ", err.Error())
			selectedPeer = ""
		} else {
			json.NewDecoder(res.Body).Decode(&EnvironmentParams)
		}
	}

	if selectedPeer == "" {
		log.Fatal("Unable to connect to blockchain, exiting")
	}

	//reading fees
	res, err := http.Get("http://" + selectedPeer + "/api/blocks/getfees")
	if err != nil {
		log.Fatal("Error receiving fees params rest from: ", selectedPeer)
	}
	json.NewDecoder(res.Body).Decode(&EnvironmentParams)

	//getting connected peer params from peer
	peerParams := strings.Split(selectedPeer, ":")
	peerRes := new(PeerResponse)
	res, err = http.Get("http://" + selectedPeer + "/api/peers/get/?ip=" + peerParams[0] + "&port=" + peerParams[1])
	if err != nil {
		log.Fatal("Error receiving peer status from: ", selectedPeer, err.Error(), res.StatusCode)
	}
	json.NewDecoder(res.Body).Decode(peerRes)
	//saving peer parameters to globals
	EnvironmentParams.Network.ActivePeer = peerRes.SinglePeer

	return "http://" + optimizePeerList(selectedPeer)
}

func optimizePeerList(selectedPeer string) string {
	tmpClient := &ArkClient{
		sling: sling.New().Client(nil).Base("http://"+selectedPeer).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}

	peerResp, err, _ := tmpClient.GetAllPeers()
	if err.ErrorObj != nil {
		log.Println("Error getting peer list")
		return selectedPeer
	}

	EnvironmentParams.Network.PeerList = peerResp.Peers
	log.Println("Start to optimize peer list, currently ", len(EnvironmentParams.Network.PeerList), " peers.")

	//setting the version condition
	//TODO - bring from settings as param
	versionString := "1.0.2"
	if EnvironmentParams.Network.Type == DEVNET {
		versionString = "1.1.1"
	} else if EnvironmentParams.Network.Type == KAPU {
		versionString = "0.3.0"
	}

	//Clean the peer list (filters not working as they shoud) - so checking again here
	maxHeight := EnvironmentParams.Network.ActivePeer.Height
	for i := len(EnvironmentParams.Network.PeerList) - 1; i >= 0; i-- {
		peer := EnvironmentParams.Network.PeerList[i]

		// Condition to decide if current element has to be deleted:
		if peer.Status != "OK" || peer.Port != EnvironmentParams.Network.ActivePeer.Port || peer.Version != versionString {
			EnvironmentParams.Network.PeerList = append(EnvironmentParams.Network.PeerList[:i], EnvironmentParams.Network.PeerList[i+1:]...)
			//log.Println("Removing peer", peer.IP, peer.Status, peer.Height)
			continue
		}
		//if all is ok and height is higher - we preffer peers with higher hight
		if peer.Height > maxHeight {
			log.Println("Setting new active peer, found OK peer with bigger block height", peer.Height, maxHeight)
			EnvironmentParams.Network.ActivePeer = peer
			selectedPeer = fmt.Sprintf("%s:%d", peer.IP, peer.Port)
			maxHeight = peer.Height
		}
	}

	//removing peers with difference more then 17 blocks, that is 10x8s behing mainheight
	for i := len(EnvironmentParams.Network.PeerList) - 1; i >= 0; i-- {
		peer := EnvironmentParams.Network.PeerList[i]

		if maxHeight-peer.Height > 17 {
			EnvironmentParams.Network.PeerList = append(EnvironmentParams.Network.PeerList[:i], EnvironmentParams.Network.PeerList[i+1:]...)
			//log.Println("Removing peer, based on maxheight difference condition", peer.IP, peer.Status, peer.Height)
			continue
		}
	}
	log.Println("End of peer optimization, remaining ", len(EnvironmentParams.Network.PeerList), " peers.")
	return selectedPeer
}

func switchNetwork(arkNetwork ArkNetworkType) {
	BaseURL = LoadActiveConfiguration(arkNetwork)
	var wifHeader = []byte{170}

	if arkNetwork == DEVNET {
		wifHeader = []byte{239}
	}

	coinParams := arkcoin.Params{
		AddressHeader:          EnvironmentParams.Network.AddressVersion,
		DumpedPrivateKeyHeader: wifHeader,
	}
	arkcoin.SetActiveCoinConfiguration(&coinParams)
}

//SetActiveConfiguration sets a new client connection, switches network and reads network settings from peer
//usage - must reassing new pointer value: arkapi = arkapi.SetActiveConfiguration(MAINNET)
func (s *ArkClient) SetActiveConfiguration(arkNetwork ArkNetworkType) *ArkClient {
	switchNetwork(arkNetwork)
	return NewArkClient(nil)
}

var seedList = [...]string{
	"172.16.17.32:4001",
	"192.168.127.12:4001",
	"192.168.3.11:4001",
	"172.16.17.32:4001",
	"192.168.3.11:4001",
	"192.168.3.11:4001",
	"192.168.127.12:4001",
	"192.168.127.12:4001",
	"192.168.127.12:4001",
	"172.16.58.3:4001",
	"192.168.127.12:4001",
	"172.16.58.3:4001",
	"172.16.17.32:4001",
	"172.16.31.10:4001",
	"172.16.17.32:4001"}

var testSeedList = [...]string{
	"172.16.17.32:4002",
	"172.16.58.3:4002",
	"192.168.3.11:4002",
	"192.168.127.12:4002",
	"172.16.58.3:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"192.168.3.11:4002",
	"192.168.127.12:4002",
	"172.16.58.3:4002",
	"192.168.3.11:4002",
	"192.168.3.11:4002",
	"172.16.31.10:4002",
	"172.16.17.32:4002",
	"192.168.127.12:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"192.168.3.11:4002",
	"172.16.31.10:4002",
	"172.16.58.3:4002",
	"172.16.17.32:4002",
	"192.168.3.11:4002",
	"172.16.58.3:4002",
	"172.16.17.32:4002",
	"192.168.3.11:4002",
	"192.168.3.11:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"172.16.58.3:4002",
	"172.16.31.10:4002",
	"172.16.58.3:4002",
	"192.168.127.12:4002",
	"192.168.127.12:4002",
	"192.168.3.11:4002",
	"172.16.58.3:4002",
	"192.168.127.12:4002",
	"172.16.17.32:4002",
	"192.168.3.11:4002",
	"172.16.58.3:4002",
	"172.16.31.10:4002",
	"172.16.58.3:4002",
	"192.168.3.11:4002",
	"192.168.127.12:4002",
	"172.16.17.32:4002",
	"172.16.17.32:4002",
	"172.16.58.3:4002",
	"172.16.31.10:4002",
	"172.16.31.10:4002",
	"192.168.3.11:4002",
	"172.16.31.10:4002"}

var seedListKAPU = [...]string{
	"172.16.31.10:4600",
	"172.16.31.10:4600",
	"172.16.31.10:4600",
	"192.168.127.12:4600",
	"192.168.3.11:4600",
	"192.168.3.11:4600",
	"172.16.58.3:4600",
	"192.168.127.12:4600",
	"172.16.58.3:4600",
	"192.168.3.11:9700",
	"192.168.3.11:4600",
	"172.16.17.32:4600",
	"172.16.17.32:4600",
	"192.168.3.11:4600",
	"172.16.17.32:4600",
	"172.16.17.32:4600",
	"172.16.17.32:4600",
	"172.16.31.10:4600",
	"192.168.127.12:4600"}

{'fraction_non_alphanumeric': 0.16135228582404917, 'fraction_numerical': 0.1294111190384721, 'mean_word_length': 3.9991769547325102, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 170, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3252637', 'n_tokens_mistral': 8340, 'n_tokens_neox': 6796, 'n_words': 1332}