Commit f1508fc2 authored by David Vorick's avatar David Vorick

move wallet and miner interfaces into their respective packages

parent 13d405f5
hostdir
release
whitepaper.aux
whitepaper.log
......
package sia
import (
"errors"
"github.com/NebulousLabs/Sia/consensus"
"github.com/NebulousLabs/Sia/network"
"github.com/NebulousLabs/Sia/sia/miner"
"github.com/NebulousLabs/Sia/sia/wallet"
)
// CoreInput is just to prevent the inputs to CreateCore() from being
......@@ -18,8 +22,8 @@ type Config struct {
// Interface implementations.
Host Host
HostDB HostDB
Miner Miner
Wallet Wallet
Miner miner.Miner
Wallet wallet.Wallet
}
// Core is the struct that serves as the state for siad. It contains a
......@@ -31,8 +35,8 @@ type Core struct {
server *network.TCPServer
host Host
hostDB HostDB
miner Miner
wallet Wallet
miner miner.Miner
wallet wallet.Wallet
// friends map[string]consensus.CoinAddress
......@@ -49,10 +53,24 @@ type Core struct {
// createCore creates a server, host, miner, renter and wallet and
// puts it all in a single environment struct that's used as the state for the
// main package.
//
// TODO: swap out the way that CreateCore is called so that the wallet,
// host, etc. can all be used as input - or not supplied at all.
func CreateCore(config Config) (c *Core, err error) {
if config.Host == nil {
err = errors.New("cannot have nil host")
return
}
if config.HostDB == nil {
err = errors.New("cannot have nil hostdb")
return
}
if config.Miner == nil {
err = errors.New("cannot have nil miner")
return
}
if config.Wallet == nil {
err = errors.New("cannot have nil wallet")
return
}
// Fill out the basic information.
c = &Core{
host: config.Host,
......
......@@ -9,7 +9,7 @@ import (
)
// establishTestingEnvrionment sets all of the testEnv variables.
func establishTestingEnvironment(t *testing.T) (e *Core) {
func establishTestingEnvironment(t *testing.T) (c *Core) {
// Alter the constants to create a system more friendly to testing.
//
// TODO: Perhaps also have these constants as a build flag, then they don't
......@@ -21,31 +21,18 @@ func establishTestingEnvironment(t *testing.T) (e *Core) {
consensus.MaxAdjustmentUp = big.NewRat(1005, 1000)
consensus.MaxAdjustmentDown = big.NewRat(995, 1000)
e, err := CreateCore("host", "test.wallet", ":9988", true)
coreConfig := Config{
HostDir: "hostdir",
WalletFile: "test.wallet",
ServerAddr: ":9988",
Nobootstrap: true,
}
c, err := CreateCore(coreConfig)
if err != nil {
t.Fatal(err)
}
/*
// Create host settings for each environment.
defaultSettings := HostAnnouncement{
MinFilesize: 1024,
MaxFilesize: 1024 * 1024,
MinDuration: 10,
MaxDuration: 1000,
MinChallengeWindow: 20,
MaxChallengeWindow: 1000,
MinTolerance: 5,
Price: 5,
Burn: 5,
}
// Create some host settings.
te.e0.host.Settings = defaultSettings
te.e0.host.Settings.IPAddress = network.NetAddress{"localhost", 9988}
te.e0.host.Settings.CoinAddress = te.e0.CoinAddress()
*/
return
}
......
package sia
import (
"github.com/NebulousLabs/Sia/consensus"
"github.com/NebulousLabs/Sia/sia/miner"
)
// MinerUpdate condenses the set of inputs to the Update() function into a
// single struct.
type MinerUpdate struct {
Parent consensus.BlockID
Transactions []consensus.Transaction
Target consensus.Target
Address consensus.CoinAddress
EarliestTimestamp consensus.Timestamp
BlockChan chan consensus.Block
Threads int
}
// The miner is used by the Core to facilitate the mining of blocks.
type Miner interface {
// Info returns an arbitrary byte slice presumably with information about
// the status of the miner. Info is not relevant to the sia package, but
// instead to the front end.
Info() ([]byte, error)
// SubsidyAddress returns the address that is currently being used by the
// miner while looking for a block.
SubsidyAddress() consensus.CoinAddress
// Update allows the state to change the block channel, the number of
// threads, and the block mining information.
//
// If MinerUpdate.Threads == 0, the number of threads is kept the same.
// There should be a cleaner way of doing this.
Update(MinerUpdate) error
// StartMining will turn on the miner and begin consuming computational
// cycles.
StartMining() error
// StopMining will turn of the miner and stop consuming computational
// cycles.
StopMining() error
// SolveBlock will attempt to solve a block, returning the most recent
// attempt and indicating whether the solve was successful or not.
SolveBlock() (block consensus.Block, solved bool, err error)
}
// StartMining calls StartMining on the miner.
func (c *Core) StartMining() error {
return c.miner.StartMining()
......@@ -79,7 +35,7 @@ func (c *Core) UpdateMiner(threads int) (err error) {
}
// Create the update struct for the miner.
update := MinerUpdate{
update := miner.MinerUpdate{
Parent: recentBlock.ID(),
Transactions: c.state.TransactionPoolDump(),
Target: c.state.CurrentTarget(),
......
......@@ -15,7 +15,7 @@ type Status struct {
// Info() returns a JSON struct which can be parsed by frontends for displaying
// information to the user.
func (m *Miner) Info() ([]byte, error) {
func (m *CPUMiner) Info() ([]byte, error) {
m.RLock()
defer m.RUnlock()
......
......@@ -8,7 +8,7 @@ import (
)
// Creates a block that is ready for nonce grinding.
func (m *Miner) blockForWork() (b consensus.Block) {
func (m *CPUMiner) blockForWork() (b consensus.Block) {
// Fill out the block with potentially ready values.
b = consensus.Block{
ParentBlockID: m.parent,
......@@ -37,7 +37,7 @@ func (m *Miner) blockForWork() (b consensus.Block) {
// function.
//
// The threading is fragile. Edit with caution!
func (m *Miner) mine() {
func (m *CPUMiner) mine() {
// Increment the number of threads running, because this thread is spinning
// up. Also grab a number that will tell us when to shut down.
m.Lock()
......@@ -71,7 +71,7 @@ func (m *Miner) mine() {
// solveBlock tries to find a solution by increasing the nonce and checking
// the hash repeatedly. Can fail.
func (m *Miner) SolveBlock() (b consensus.Block, solved bool, err error) {
func (m *CPUMiner) SolveBlock() (b consensus.Block, solved bool, err error) {
m.RLock()
b = m.blockForWork()
m.RUnlock()
......@@ -88,7 +88,7 @@ func (m *Miner) SolveBlock() (b consensus.Block, solved bool, err error) {
// StartMining spawns a bunch of mining threads which will mine until stop is
// called.
func (m *Miner) StartMining() error {
func (m *CPUMiner) StartMining() error {
m.Lock()
defer m.Unlock()
......@@ -103,7 +103,7 @@ func (m *Miner) StartMining() error {
// StopMining sets desiredThreads to 0, a value which is polled by mining
// threads. When set to 0, the mining threads will all cease mining.
func (m *Miner) StopMining() error {
func (m *CPUMiner) StopMining() error {
m.Lock()
defer m.Unlock()
......
package miner
import (
"runtime"
"sync"
"github.com/NebulousLabs/Sia/consensus"
)
// Might want to switch to having a settings variable.
type CPUMiner struct {
// Block variables - helps the miner construct the next block.
parent consensus.BlockID
transactions []consensus.Transaction
address consensus.CoinAddress
target consensus.Target
earliestTimestamp consensus.Timestamp
threads int // how many threads the miner usually uses.
desiredThreads int // 0 if not mining.
runningThreads int
iterationsPerAttempt uint64
blockChan chan consensus.Block
sync.RWMutex
}
// New takes a block channel down which it drops blocks that it mines. It also
// takes a thread count, which it uses to spin up miners on separate threads.
func New() (m *CPUMiner) {
return &CPUMiner{
iterationsPerAttempt: 256 * 1024,
}
}
// SubsidyAddress returns the address that is currently being used by the miner
// while searching for blocks.
func (m *CPUMiner) SubsidyAddress() consensus.CoinAddress {
m.Lock()
defer m.Unlock()
return m.address
}
// Update changes what block the miner is mining on. Changes include address
// and target.
func (m *CPUMiner) Update(mu MinerUpdate) error {
m.Lock()
defer m.Unlock()
m.parent = mu.Parent
m.transactions = mu.Transactions
m.target = mu.Target
m.address = mu.Address
m.earliestTimestamp = mu.EarliestTimestamp
if mu.Threads != 0 {
m.threads = mu.Threads
runtime.GOMAXPROCS(mu.Threads)
}
m.blockChan = mu.BlockChan
return nil
}
package miner
import (
"runtime"
"sync"
"github.com/NebulousLabs/Sia/consensus"
"github.com/NebulousLabs/Sia/sia"
)
// Might want to switch to having a settings variable.
type Miner struct {
// Block variables - helps the miner construct the next block.
parent consensus.BlockID
transactions []consensus.Transaction
address consensus.CoinAddress
target consensus.Target
earliestTimestamp consensus.Timestamp
threads int // how many threads the miner usually uses.
desiredThreads int // 0 if not mining.
runningThreads int
iterationsPerAttempt uint64
blockChan chan consensus.Block
sync.RWMutex
// MinerUpdate condenses the set of inputs to the Update() function into a
// single struct.
type MinerUpdate struct {
Parent consensus.BlockID
Transactions []consensus.Transaction
Target consensus.Target
Address consensus.CoinAddress
EarliestTimestamp consensus.Timestamp
BlockChan chan consensus.Block
Threads int
}
// New takes a block channel down which it drops blocks that it mines. It also
// takes a thread count, which it uses to spin up miners on separate threads.
func New() (m *Miner) {
return &Miner{
iterationsPerAttempt: 256 * 1024,
}
}
// SubsidyAddress returns the address that is currently being used by the miner
// while searching for blocks.
func (m *Miner) SubsidyAddress() consensus.CoinAddress {
m.Lock()
defer m.Unlock()
return m.address
}
// Update changes what block the miner is mining on. Changes include address
// and target.
func (m *Miner) Update(mu sia.MinerUpdate) error {
m.Lock()
defer m.Unlock()
m.parent = mu.Parent
m.transactions = mu.Transactions
m.target = mu.Target
m.address = mu.Address
m.earliestTimestamp = mu.EarliestTimestamp
if mu.Threads != 0 {
m.threads = mu.Threads
runtime.GOMAXPROCS(mu.Threads)
}
m.blockChan = mu.BlockChan
return nil
// The miner is used by the Core to facilitate the mining of blocks.
type Miner interface {
// Info returns an arbitrary byte slice presumably with information about
// the status of the miner. Info is not relevant to the sia package, but
// instead to the front end.
Info() ([]byte, error)
// SubsidyAddress returns the address that is currently being used by the
// miner while looking for a block.
SubsidyAddress() consensus.CoinAddress
// Update allows the state to change the block channel, the number of
// threads, and the block mining information.
//
// If MinerUpdate.Threads == 0, the number of threads is kept the same.
// There should be a cleaner way of doing this.
Update(MinerUpdate) error
// StartMining will turn on the miner and begin consuming computational
// cycles.
StartMining() error
// StopMining will turn of the miner and stop consuming computational
// cycles.
StopMining() error
// SolveBlock will attempt to solve a block, returning the most recent
// attempt and indicating whether the solve was successful or not.
SolveBlock() (block consensus.Block, solved bool, err error)
}
......@@ -4,74 +4,6 @@ import (
"github.com/NebulousLabs/Sia/consensus"
)
// Wallet in an interface that helps to build and sign transactions. The user
// can make a new transaction-in-progress by calling Register(), and then can
// add outputs, fees, etc.
type Wallet interface {
// Info takes zero arguments and returns an arbitrary set of information
// about the wallet in the form of json. The frontend will have to know how
// to parse it, but Core and Daemon don't need to understand what's in the
// json.
Info() ([]byte, error)
// Update takes two sets of blocks. The first is the set of blocks that
// have been rewound since the previous call to update, and the second set
// is the blocks that were applied after rewinding.
Update([]consensus.OutputDiff) error
// Reset will clear the list of spent transactions, which is nice if you've
// accidentally made transactions that aren't spreading on the network for
// whatever reason (for example, 0 fee transaction, or if there are bugs in
// the software). Reset will also destroy all in-progress transactions.
Reset() error
// Balance returns the total number of coins accessible to the wallet. If
// full == true, the number of coins returned will also include coins that
// have been spent in unconfirmed transactions.
Balance(full bool) consensus.Currency
// CoinAddress return an address into which coins can be paid.
CoinAddress() (consensus.CoinAddress, error)
// RegisterTransaction creates a transaction out of an existing transaction
// which can be modified by the wallet, returning an id that can be used to
// reference the transaction.
RegisterTransaction(consensus.Transaction) (id string, err error)
// FundTransaction will add `amount` to a transaction's inputs.
FundTransaction(id string, amount consensus.Currency) error
// AddMinerFee adds a single miner fee of value `fee`.
AddMinerFee(id string, fee consensus.Currency) error
// AddOutput adds an output to a transaction.
AddOutput(id string, output consensus.Output) error
// AddTimelockedOutput will create an output with coins that are locked
// until block `release`. The spend conditions are returned so that they
// can be shown as proof that coins have been timelocked.
AddTimelockedOutput(id string, amount consensus.Currency, dest consensus.CoinAddress, release consensus.BlockHeight) (sc consensus.SpendConditions, refundIndex uint64, err error)
// AddFileContract adds a file contract to a transaction.
AddFileContract(id string, fc consensus.FileContract) error
// AddStorageProof adds a storage proof to a transaction.
AddStorageProof(id string, sp consensus.StorageProof) error
// AddArbitraryData adds a byte slice to the arbitrary data section of the
// transaction.
AddArbitraryData(id string, arb string) error
// Sign transaction will sign the transaction associated with the id and
// then return the transaction. If wholeTransaction is set to true, then
// the wholeTransaction flag will be set in CoveredFields for each
// signature.
//
// Upon being signed and returned, the transaction-in-progress is deleted
// from the wallet.
SignTransaction(id string, wholeTransaction bool) (consensus.Transaction, error)
}
// SpendCoins creates a transaction sending 'amount' to 'dest', and
// allocateding 'minerFee' as a miner fee. The transaction is submitted to the
// miner pool, but is also returned.
......
......@@ -7,7 +7,7 @@ import (
// timelockedCoinAddress returns a CoinAddress with a timelock, as well as the
// conditions needed to spend it.
func (w *Wallet) timelockedCoinAddress(release consensus.BlockHeight) (spendConditions consensus.SpendConditions, err error) {
func (w *BasicWallet) timelockedCoinAddress(release consensus.BlockHeight) (spendConditions consensus.SpendConditions, err error) {
sk, pk, err := signatures.GenerateKeyPair()
if err != nil {
return
......@@ -30,8 +30,8 @@ func (w *Wallet) timelockedCoinAddress(release consensus.BlockHeight) (spendCond
return
}
// CoinAddress implements the core.Wallet interface.
func (w *Wallet) CoinAddress() (coinAddress consensus.CoinAddress, err error) {
// CoinAddress implements the core.BasicWallet interface.
func (w *BasicWallet) CoinAddress() (coinAddress consensus.CoinAddress, err error) {
w.Lock()
defer w.Unlock()
......
package wallet
import (
"encoding/json"
"sync"
"github.com/NebulousLabs/Sia/consensus"
)
// BasicWallet holds your coins, manages privacy, outputs, ect. The balance reported
// ignores outputs you've already spent even if they haven't made it into the
// blockchain yet.
//
// The spentCounter is used to indicate which transactions have been spent but
// have not appeared in the blockchain. It's used as an int for an easy reset.
// Each transaction also has a spent counter. If the transaction's spent
// counter is equal to the wallet's spent counter, then the transaction has
// been spent since the last reset. Upon reset, the wallet's spent counter is
// incremented, which means all transactions will no longer register as having
// been spent since the last reset.
//
// BasicWallet.transactions is a list of transactions that are currently being built
// within the wallet. The transactionCounter ensures that each
// transaction-in-progress gets a unique ID.
type BasicWallet struct {
saveFilename string
spentCounter int
spendableAddresses map[consensus.CoinAddress]*spendableAddress
transactionCounter int
transactions map[string]*openTransaction
sync.RWMutex
}
type Status struct {
Balance consensus.Currency
FullBalance consensus.Currency
NumAddresses int
}
// New creates a new wallet, loading any known addresses from the input file
// name and then using the file to save in the future.
func New(filename string) (w *BasicWallet, err error) {
w = &BasicWallet{
spentCounter: 1,
saveFilename: filename,
spendableAddresses: make(map[consensus.CoinAddress]*spendableAddress),
transactions: make(map[string]*openTransaction),
}
err = w.Load(filename)
if err != nil {
return
}
return
}
// Info implements the core.BasicWallet interface.
func (w *BasicWallet) Info() ([]byte, error) {
w.RLock()
defer w.RUnlock()
status := Status{
Balance: w.Balance(false),
FullBalance: w.Balance(true),
}
status.NumAddresses = len(w.spendableAddresses)
return json.Marshal(status)
}
package wallet
import (
"io/ioutil"
"os"
"github.com/NebulousLabs/Sia/consensus"
"github.com/NebulousLabs/Sia/encoding"
"github.com/NebulousLabs/Sia/signatures"
)
// AddressKey is how we serialize and store spendable addresses on
// disk.
type AddressKey struct {
......@@ -7,8 +16,8 @@ type AddressKey struct {
SecretKey signatures.SecretKey
}
// Save implements the core.Wallet interface.
func (w *Wallet) Save() (err error) {
// Save implements the core.BasicWallet interface.
func (w *BasicWallet) Save() (err error) {
// Add every known spendable address + secret key.
var i int
keys := make([]AddressKey, len(w.spendableAddresses))
......@@ -30,8 +39,8 @@ func (w *Wallet) Save() (err error) {
return
}
// Load implements the core.Wallet interface.
func (w *Wallet) Load(filename string) (err error) {
// Load implements the core.BasicWallet interface.
func (w *BasicWallet) Load(filename string) (err error) {
// Check if the file exists, then read it into memory.
if _, err = os.Stat(filename); os.IsNotExist(err) {
err = nil
......@@ -56,4 +65,5 @@ func (w *Wallet) Load(filename string) (err error) {
}
w.spendableAddresses[key.SpendConditions.CoinAddress()] = newSpendableAddress
}
return
}
......@@ -40,7 +40,7 @@ type spendableAddress struct {
// `amount` of coins, returning an error if it cannot. It also returns the
// `total`, which is the sum of all the outputs. It does not adjust the outputs
// in any way.
func (w *Wallet) findOutputs(amount consensus.Currency) (spendableOutputs []*spendableOutput, total consensus.Currency, err error) {
func (w *BasicWallet) findOutputs(amount consensus.Currency) (spendableOutputs []*spendableOutput, total consensus.Currency, err error) {
if amount == consensus.Currency(0) {
err = errors.New("cannot fund 0 coins") // should this be an error or nil?
return
......@@ -67,8 +67,8 @@ func (w *Wallet) findOutputs(amount consensus.Currency) (spendableOutputs []*spe
return
}
// Balance implements the core.Wallet interface.
func (w *Wallet) Balance(full bool) (total consensus.Currency) {
// Balance implements the core.BasicWallet interface.
func (w *BasicWallet) Balance(full bool) (total consensus.Currency) {
w.RLock()
defer w.RUnlock()
......@@ -87,8 +87,8 @@ func (w *Wallet) Balance(full bool) (total consensus.Currency) {
return
}
// Update implements the core.Wallet interface.
func (w *Wallet) Update(diffs []consensus.OutputDiff) error {
// Update implements the core.BasicWallet interface.
func (w *BasicWallet) Update(diffs []consensus.OutputDiff) error {
w.Lock()
defer w.Unlock()
......
......@@ -8,8 +8,8 @@ import (
"github.com/NebulousLabs/Sia/signatures"
)
// Reset implements the core.Wallet interface.
func (w *Wallet) Reset() error {
// Reset implements the core.BasicWallet interface.
func (w *BasicWallet) Reset() error {
w.Lock()
defer w.Unlock()
......@@ -19,8 +19,8 @@ func (w *Wallet) Reset() error {
return nil
}
// RegisterTransaction implements the core.Wallet interface.
func (w *Wallet) RegisterTransaction(t consensus.Transaction) (id string, err error) {
// RegisterTransaction implements the core.BasicWallet interface.
func (w *BasicWallet) RegisterTransaction(t consensus.Transaction) (id string, err error) {
w.Lock()
defer w.Unlock()
......@@ -31,8 +31,8 @@ func (w *Wallet) RegisterTransaction(t consensus.Transaction) (id string, err er
return
}
// FundTransaction implements the core.Wallet interface.
func (w *Wallet) FundTransaction(id string, amount consensus.Currency) error {
// FundTransaction implements the core.BasicWallet interface.
func (w *BasicWallet) FundTransaction(id string, amount consensus.Currency) error {
w.Lock()
defer w.Unlock()
......@@ -81,8 +81,8 @@ func (w *Wallet) FundTransaction(id string, amount consensus.Currency) error {
return nil
}
// AddMinerFee implements the core.Wallet interface.
func (w *Wallet) AddMinerFee(id string, fee consensus.Currency) error {
// AddMinerFee implements the core.BasicWallet interface.
func (w *BasicWallet) AddMinerFee(id string, fee consensus.Currency) error {
w.Lock()
defer w.Unlock()
......@@ -95,8 +95,8 @@ func (w *Wallet) AddMinerFee(id string, fee consensus.Currency) error {
return nil
}
// AddOutput implements the core.Wallet interface.
func (w *Wallet) AddOutput(id string, o consensus.Output) error {
// AddOutput implements the core.BasicWallet interface.
func (w *BasicWallet) AddOutput(id string, o consensus.Output) error {
w.Lock()
defer w.Unlock()
......@@ -109,8 +109,8 @@ func (w *Wallet) AddOutput(id string, o consensus.Output) error {
return nil
}
// AddTimelockedRefund implements the core.Wallet interface.
func (w *Wallet) AddTimelockedRefund(id string, amount consensus.Currency, release consensus.BlockHeight) (spendConditions consensus.SpendConditions, refundIndex uint64, err error) {
// AddTimelockedRefund implements the core.BasicWallet interface.
func (w *BasicWallet) AddTimelockedRefund(id string, amount consensus.Currency, release consensus.BlockHeight) (spendConditions consensus.SpendConditions, refundIndex uint64, err error) {
w.Lock()
defer w.Unlock()
......@@ -138,8 +138,8 @@ func (w *Wallet) AddTimelockedRefund(id string, amount consensus.Currency, relea
return
}
// AddFileContract implements the core.Wallet interface.
func (w *Wallet) AddFileContract(id string, fc consensus.FileContract) error {
// AddFileContract implements the core.BasicWallet interface.
func (w *BasicWallet) AddFileContract(id string, fc consensus.FileContract) error {
w.Lock()
defer w.Unlock()
......@@ -152,8 +152,8 @@ func (w *Wallet) AddFileContract(id string, fc consensus.FileContract) error {
return nil
}
// AddStorageProof implements the core.Wallet interface.
func (w *Wallet) AddStorageProof(id string, sp consensus.StorageProof) error {
// AddStorageProof implements the core.BasicWallet interface.
func (w *BasicWallet) AddStorageProof(id string, sp consensus.StorageProof) error {
w.Lock()
defer w.Unlock()
......@@ -166,8 +166,8 @@ func (w *Wallet) AddStorageProof(id string, sp consensus.StorageProof) error {
return nil
}
// AddArbitraryData implements the core.Wallet interface.
func (w *Wallet) AddArbitraryData(id string, arb string) error {
// AddArbitraryData implements the core.BasicWallet interface.
func (w *BasicWallet) AddArbitraryData(id string, arb string) error {
w.Lock()
defer w.Unlock()
......@@ -180,8 +180,8 @@ func (w *Wallet) AddArbitraryData(id string, arb string) error {
return nil
}
// SignTransaction implements the core.Wallet interface.
func (w *Wallet) SignTransaction(id string, wholeTransaction bool) (transaction consensus.Transaction, err error) {
// SignTransaction implements the core.BasicWallet interface.
func (w *BasicWallet) SignTransaction(id string, wholeTransaction bool) (transaction consensus.Transaction, err error) {
w.Lock()
defer w.Unlock()