Exemple #1
0
func TestCurrencyUnits(t *testing.T) {
	tests := []struct {
		in, out string
	}{
		{"1", "1 H"},
		{"1000", "1000 H"},
		{"100000000000", "100000000000 H"},
		{"1000000000000", "1 pS"},
		{"1234560000000", "1.235 pS"},
		{"12345600000000", "12.35 pS"},
		{"123456000000000", "123.5 pS"},
		{"1000000000000000", "1 nS"},
		{"1000000000000000000", "1 uS"},
		{"1000000000000000000000", "1 mS"},
		{"1000000000000000000000000", "1 SC"},
		{"1000000000000000000000000000", "1 KS"},
		{"1000000000000000000000000000000", "1 MS"},
		{"1000000000000000000000000000000000", "1 GS"},
		{"1000000000000000000000000000000000000", "1 TS"},
		{"1234560000000000000000000000000000000", "1.235 TS"},
		{"1234560000000000000000000000000000000000", "1235 TS"},
	}
	for _, test := range tests {
		i, _ := new(big.Int).SetString(test.in, 10)
		out := currencyUnits(types.NewCurrency(i))
		if out != test.out {
			t.Errorf("currencyUnits(%v): expected %v, got %v", test.in, test.out, out)
		}
	}
}
Exemple #2
0
// RandomHosts will pull up to 'num' random hosts from the hostdb. There will
// be no repeats, but the length of the slice returned may be less than 'num',
// and may even be 0. The hosts that get returned first have the higher
// priority.
func (hdb *HostDB) RandomHosts(count int) (hosts []modules.HostSettings) {
	id := hdb.mu.Lock()
	defer hdb.mu.Unlock(id)

	var removedEntries []*hostEntry
	for len(hosts) < count {
		if hdb.hostTree == nil || hdb.hostTree.weight.IsZero() {
			break
		}
		randWeight, err := rand.Int(rand.Reader, hdb.hostTree.weight.Big())
		if err != nil {
			break
		}
		node, err := hdb.hostTree.nodeAtWeight(types.NewCurrency(randWeight))
		if err != nil {
			break
		}
		hosts = append(hosts, node.hostEntry.HostSettings)
		node.removeNode()
		delete(hdb.activeHosts, node.hostEntry.IPAddress)

		// remove the entry from the hostdb so it won't be selected as a
		// repeat.
		removedEntries = append(removedEntries, node.hostEntry)
	}

	// Add back all of the entries that got removed.
	for _, entry := range removedEntries {
		hdb.insertNode(entry)
	}
	return hosts
}
Exemple #3
0
// scanAmount scans a types.Currency from a string.
func scanAmount(amount string) (types.Currency, bool) {
	// use SetString manually to ensure that amount does not contain
	// multiple values, which would confuse fmt.Scan
	i, ok := new(big.Int).SetString(amount, 10)
	if !ok {
		return types.Currency{}, ok
	}
	return types.NewCurrency(i), true
}
Exemple #4
0
// hostconfigcmd is the handler for the command `siac host config [setting] [value]`.
// Modifies host settings.
func hostconfigcmd(param, value string) {
	switch param {
	// currency (convert to hastings)
	case "collateralbudget", "maxcollateral", "mincontractprice":
		hastings, err := parseCurrency(value)
		if err != nil {
			die("Could not parse "+param+":", err)
		}
		value = hastings

	// currency/TB (convert to hastings/byte)
	case "mindownloadbandwidthprice", "minuploadbandwidthprice":
		hastings, err := parseCurrency(value)
		if err != nil {
			die("Could not parse "+param+":", err)
		}
		i, _ := new(big.Int).SetString(hastings, 10)
		c := types.NewCurrency(i).Div(modules.BytesPerTerabyte)
		value = c.String()

	// currency/TB/month (convert to hastings/byte/block)
	case "collateral", "minstorageprice":
		hastings, err := parseCurrency(value)
		if err != nil {
			die("Could not parse "+param+":", err)
		}
		i, _ := new(big.Int).SetString(hastings, 10)
		c := types.NewCurrency(i).Div(modules.BlockBytesPerMonthTerabyte)
		value = c.String()

	// other valid settings
	case "acceptingcontracts", "maxdownloadbatchsize", "maxduration",
		"maxrevisebatchsize", "netaddress", "windowsize":

	// invalid settings
	default:
		die("\"" + param + "\" is not a host setting")
	}
	err := post("/host", param+"="+value)
	if err != nil {
		die("Could not update host settings:", err)
	}
	fmt.Println("Host settings updated.")
}
Exemple #5
0
// Returns many pieces of readily available information
func (e *Explorer) Statistics() modules.ExplorerStatistics {
	e.mu.RLock()
	defer e.mu.RUnlock()

	target, _ := e.cs.ChildTarget(e.currentBlock)
	difficulty := types.NewCurrency(types.RootTarget.Int()).Div(types.NewCurrency(target.Int()))
	currentBlock, exists := e.cs.BlockAtHeight(e.blockchainHeight)
	if build.DEBUG && !exists {
		panic("current block not found in consensus set")
	}
	return modules.ExplorerStatistics{
		Height:            e.blockchainHeight,
		CurrentBlock:      e.currentBlock,
		Target:            target,
		Difficulty:        difficulty,
		MaturityTimestamp: currentBlock.Timestamp,
		TotalCoins:        types.CalculateNumSiacoins(e.blockchainHeight),

		MinerPayoutCount:          e.minerPayoutCount,
		TransactionCount:          e.transactionCount,
		SiacoinInputCount:         e.siacoinInputCount,
		SiacoinOutputCount:        e.siacoinOutputCount,
		FileContractCount:         e.fileContractCount,
		FileContractRevisionCount: e.fileContractRevisionCount,
		StorageProofCount:         e.storageProofCount,
		SiafundInputCount:         e.siafundInputCount,
		SiafundOutputCount:        e.siafundOutputCount,
		MinerFeeCount:             e.minerFeeCount,
		ArbitraryDataCount:        e.arbitraryDataCount,
		TransactionSignatureCount: e.transactionSignatureCount,

		ActiveContractCount: e.activeContractCount,
		ActiveContractCost:  e.activeContractCost,
		ActiveContractSize:  e.activeContractSize,
		TotalContractCost:   e.totalContractCost,
		TotalContractSize:   e.totalContractSize,
	}
}
Exemple #6
0
// RandomHosts will pull up to 'n' random hosts from the hostdb. There will be
// no repeats, but the length of the slice returned may be less than 'n', and
// may even be 0. The hosts that get returned first have the higher priority.
// Hosts specified in 'ignore' will not be considered; pass 'nil' if no
// blacklist is desired.
func (hdb *HostDB) RandomHosts(n int, ignore []modules.NetAddress) (hosts []modules.HostDBEntry) {
	hdb.mu.Lock()
	defer hdb.mu.Unlock()
	if hdb.isEmpty() {
		return
	}

	// These will be restored after selection is finished.
	var removedEntries []*hostEntry

	// Remove hosts that we want to ignore.
	for _, addr := range ignore {
		node, exists := hdb.activeHosts[addr]
		if !exists {
			continue
		}
		node.removeNode()
		delete(hdb.activeHosts, addr)
		removedEntries = append(removedEntries, node.hostEntry)
	}

	// Pick a host, remove it from the tree, and repeat until we have n hosts
	// or the tree is empty.
	for len(hosts) < n && !hdb.isEmpty() {
		randWeight, err := rand.Int(rand.Reader, hdb.hostTree.weight.Big())
		if err != nil {
			build.Critical("rand.Int is returning an error:", err)
			break
		}
		node, err := hdb.hostTree.nodeAtWeight(types.NewCurrency(randWeight))
		if err != nil {
			build.Critical("nodeAtWeight is returning and error:", err)
			break
		}
		// Only return the host if they are accepting contracts.
		if node.hostEntry.HostDBEntry.AcceptingContracts {
			hosts = append(hosts, node.hostEntry.HostDBEntry)
		}

		removedEntries = append(removedEntries, node.hostEntry)
		node.removeNode()
		delete(hdb.activeHosts, node.hostEntry.NetAddress)
	}

	// Add back all of the entries that got removed.
	for i := range removedEntries {
		hdb.insertNode(removedEntries[i])
	}
	return hosts
}
Exemple #7
0
// randomHosts will pull up to 'n' random hosts from the hostdb. There will be
// no repeats, but the length of the slice returned may be less than 'n', and
// may even be 0. The hosts that get returned first have the higher priority.
// Hosts specified in 'ignore' will not be considered; pass 'nil' if no
// blacklist is desired.
func (hdb *HostDB) randomHosts(n int, ignore []modules.NetAddress) (hosts []modules.HostSettings) {
	if hdb.isEmpty() {
		return
	}

	// These will be restored after selection is finished.
	var removedEntries []*hostEntry

	// Remove hosts that we want to ignore.
	for _, addr := range ignore {
		node, exists := hdb.activeHosts[addr]
		if !exists {
			continue
		}
		node.removeNode()
		delete(hdb.activeHosts, addr)
		removedEntries = append(removedEntries, node.hostEntry)
	}

	// Pick a host, remove it from the tree, and repeat until we have n hosts
	// or the tree is empty.
	for len(hosts) < n && !hdb.isEmpty() {
		randWeight, err := rand.Int(rand.Reader, hdb.hostTree.weight.Big())
		if err != nil {
			break
		}
		node, err := hdb.hostTree.nodeAtWeight(types.NewCurrency(randWeight))
		if err != nil {
			break
		}
		hosts = append(hosts, node.hostEntry.HostSettings)

		node.removeNode()
		delete(hdb.activeHosts, node.hostEntry.NetAddress)
		removedEntries = append(removedEntries, node.hostEntry)
	}

	// Add back all of the entries that got removed.
	for i := range removedEntries {
		hdb.insertNode(removedEntries[i])
	}
	return hosts
}
Exemple #8
0
// uniformTreeVerification checks that everything makes sense in the tree given
// the number of entries that the tree is supposed to have and also given that
// every entropy has the same weight.
func (hdbt *hdbTester) uniformTreeVerification(numEntries int) error {
	// Check that the weight of the hostTree is what is expected.
	expectedWeight := types.NewCurrency64(uint64(numEntries)).Mul(hdbt.hostdb.hostTree.hostEntry.weight)
	if hdbt.hostdb.hostTree.weight.Cmp(expectedWeight) != 0 {
		return errors.New("expected weight is incorrect")
	}

	// Check that the length of activeHosts and the count of hostTree are
	// consistent.
	if len(hdbt.hostdb.activeHosts) != numEntries {
		return errors.New("unexpected number of active hosts")
	}

	// Select many random hosts and do naive statistical analysis on the
	// results.
	if !testing.Short() {
		// Pull a bunch of random hosts and count how many times we pull each
		// host.
		selectionMap := make(map[modules.NetAddress]int)
		expected := 100
		for i := 0; i < expected*numEntries; i++ {
			entries := hdbt.hostdb.RandomHosts(1)
			if len(entries) == 0 {
				return errors.New("no hosts!")
			}
			selectionMap[entries[0].IPAddress] = selectionMap[entries[0].IPAddress] + 1
		}

		// See if each host was selected enough times.
		errorBound := 64 // Pretty large, but will still detect if something is seriously wrong.
		for _, count := range selectionMap {
			if count < expected-errorBound || count > expected+errorBound {
				return errors.New("error bound was breached")
			}
		}
	}

	// Try removing an re-adding all hosts.
	var removedEntries []*hostEntry
	for {
		if hdbt.hostdb.hostTree.weight.IsZero() {
			break
		}
		randWeight, err := rand.Int(rand.Reader, hdbt.hostdb.hostTree.weight.Big())
		if err != nil {
			break
		}
		node, err := hdbt.hostdb.hostTree.nodeAtWeight(types.NewCurrency(randWeight))
		if err != nil {
			break
		}
		node.removeNode()
		delete(hdbt.hostdb.activeHosts, node.hostEntry.IPAddress)

		// remove the entry from the hostdb so it won't be selected as a
		// repeat.
		removedEntries = append(removedEntries, node.hostEntry)
	}
	for _, entry := range removedEntries {
		hdbt.hostdb.insertNode(entry)
	}
	return nil
}
Exemple #9
0
package hostdb

import (
	"math/big"

	"github.com/NebulousLabs/Sia/types"
)

var (
	// Because most weights would otherwise be fractional, we set the base
	// weight to 10^80 to give ourselves lots of precision when determing the
	// weight of a host
	baseWeight = types.NewCurrency(new(big.Int).Exp(big.NewInt(10), big.NewInt(150), nil))
)

// calculateHostWeight returns the weight of a host according to the settings of
// the host database entry. Currently, only the price is considered.
func calculateHostWeight(entry hostEntry) (weight types.Currency) {
	// If the price is 0, just return the base weight to avoid divide by zero.
	price := entry.Price
	if price.IsZero() {
		return baseWeight
	}

	// Divide the base weight by the price to the fifth power.
	return baseWeight.Div(price).Div(price).Div(price).Div(price).Div(price)
}