Skip to content
This repository has been archived by the owner on Dec 3, 2018. It is now read-only.

add wallet bigsupplier and littlespender jobs #58

Merged
merged 1 commit into from
Mar 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions ant/ant.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package ant

import (
"errors"
"log"
"net"
"os/exec"

"github.com/NebulousLabs/Sia/api"
"github.com/NebulousLabs/Sia/types"
"github.com/NebulousLabs/go-upnp"
)
Expand All @@ -27,6 +29,8 @@ type Ant struct {
APIAddr string
RPCAddr string

Config AntConfig

siad *exec.Cmd
jr *jobRunner

Expand Down Expand Up @@ -114,6 +118,7 @@ func New(config AntConfig) (*Ant, error) {
return &Ant{
APIAddr: config.APIAddr,
RPCAddr: config.RPCAddr,
Config: config,

siad: siad,
jr: j,
Expand All @@ -130,6 +135,33 @@ func (a *Ant) Close() error {
return nil
}

// StartJob starts the job indicated by `job` after an ant has been
// initialized. Arguments are passed to the job using args.
func (a *Ant) StartJob(job string, args ...interface{}) error {
if a.jr == nil {
return errors.New("ant is not running")
}

switch job {
case "miner":
go a.jr.blockMining()
case "host":
go a.jr.jobHost()
case "renter":
go a.jr.storageRenter()
case "gateway":
go a.jr.gatewayConnectability()
case "bigspender":
go a.jr.bigSpender()
case "littlesupplier":
go a.jr.littleSupplier(args[0].(types.UnlockHash))
default:
return errors.New("no such job")
}

return nil
}

// BlockHeight returns the highest block height seen by the ant.
func (a *Ant) BlockHeight() types.BlockHeight {
height := types.BlockHeight(0)
Expand All @@ -140,3 +172,17 @@ func (a *Ant) BlockHeight() types.BlockHeight {
}
return height
}

// WalletAddress returns a wallet address that this ant can receive coins on.
func (a *Ant) WalletAddress() (*types.UnlockHash, error) {
if a.jr == nil {
return nil, errors.New("ant is not running")
}

var addressGet api.WalletAddressGET
if err := a.jr.client.Get("/wallet/address", &addressGet); err != nil {
return nil, err
}

return &addressGet.Address, nil
}
60 changes: 60 additions & 0 deletions ant/ant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

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

func TestNewAnt(t *testing.T) {
Expand Down Expand Up @@ -33,3 +34,62 @@ func TestNewAnt(t *testing.T) {
t.Fatal(err)
}
}

func TestStartJob(t *testing.T) {
datadir, err := ioutil.TempDir("", "testing-data")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(datadir)

config := AntConfig{
APIAddr: "localhost:31337",
RPCAddr: "localhost:31338",
HostAddr: "localhost:31339",
SiaDirectory: datadir,
SiadPath: "siad",
}

ant, err := New(config)
if err != nil {
t.Fatal(err)
}
defer ant.Close()

// nonexistent job should throw an error
err = ant.StartJob("thisjobdoesnotexist")
if err == nil {
t.Fatal("StartJob should return an error with a nonexistent job")
}
}

func TestWalletAddress(t *testing.T) {
datadir, err := ioutil.TempDir("", "testing-data")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(datadir)

config := AntConfig{
APIAddr: "localhost:31337",
RPCAddr: "localhost:31338",
HostAddr: "localhost:31339",
SiaDirectory: datadir,
SiadPath: "siad",
}

ant, err := New(config)
if err != nil {
t.Fatal(err)
}
defer ant.Close()

addr, err := ant.WalletAddress()
if err != nil {
t.Fatal(err)
}
blankaddr := types.UnlockHash{}
if *addr == blankaddr {
t.Fatal("WalletAddress returned an empty address")
}
}
49 changes: 49 additions & 0 deletions ant/job_wallet_bigspender.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ant

import (
"fmt"
"log"
"time"

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

var (
spendInterval = time.Second * 30
spendThreshold = types.NewCurrency64(5e4).Mul(types.SiacoinPrecision)
)

func (j *jobRunner) bigSpender() {
j.tg.Add()
defer j.tg.Done()

for {
select {
case <-j.tg.StopChan():
return
case <-time.After(spendInterval):
}

var walletGet api.WalletGET
if err := j.client.Get("/wallet", &walletGet); err != nil {
log.Printf("[%v jobSpender ERROR]: %v\n", j.siaDirectory, err)
return
}

if walletGet.ConfirmedSiacoinBalance.Cmp(spendThreshold) < 0 {
continue
}

log.Printf("[%v jobSpender INFO]: sending a large transaction\n", j.siaDirectory)

voidaddress := types.UnlockHash{}
err := j.client.Post("/wallet/siacoins", fmt.Sprintf("amount=%v&destination=%v", spendThreshold, voidaddress), nil)
if err != nil {
log.Printf("[%v jobSpender ERROR]: %v\n", j.siaDirectory, err)
continue
}

log.Printf("[%v jobSpender INFO]: large transaction send successful\n", j.siaDirectory)
}
}
43 changes: 43 additions & 0 deletions ant/job_wallet_littlesupplier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ant

import (
"fmt"
"log"
"time"

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

var (
sendInterval = time.Second * 2
sendAmount = types.NewCurrency64(1000).Mul(types.SiacoinPrecision)
)

func (j *jobRunner) littleSupplier(sendAddress types.UnlockHash) {
j.tg.Add()
defer j.tg.Done()

for {
select {
case <-j.tg.StopChan():
return
case <-time.After(sendInterval):
}

var walletGet api.WalletGET
if err := j.client.Get("/wallet", &walletGet); err != nil {
log.Printf("[%v jobSpender ERROR]: %v\n", j.siaDirectory, err)
return
}

if walletGet.ConfirmedSiacoinBalance.Cmp(sendAmount) < 0 {
continue
}

err := j.client.Post("/wallet/siacoins", fmt.Sprintf("amount=%v&destination=%v", sendAmount, sendAddress), nil)
if err != nil {
log.Printf("[%v jobSupplier ERROR]: %v\n", j.siaDirectory, err)
}
}
}
36 changes: 36 additions & 0 deletions sia-antfarm/ant.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,42 @@ func startAnts(configs ...ant.AntConfig) ([]*ant.Ant, error) {
return ants, nil
}

// startJobs starts all the jobs for each ant.
func startJobs(ants ...*ant.Ant) error {
// first, pull out any constants needed for the jobs
var spenderAddress *types.UnlockHash
for _, ant := range ants {
for _, job := range ant.Config.Jobs {
if job == "bigspender" {
addr, err := ant.WalletAddress()
if err != nil {
return err
}
spenderAddress = addr
}
}
}
// start jobs requiring those constants
for _, ant := range ants {
for _, job := range ant.Config.Jobs {
if job == "bigspender" {
ant.StartJob(job)
}
if job == "littlesupplier" && spenderAddress != nil {
err := ant.StartJob(job, *spenderAddress)
if err != nil {
return err
}
err = ant.StartJob("miner")
if err != nil {
return err
}
}
}
}
return nil
}

// parseConfig takes an input `config` and fills it with default values if
// required.
func parseConfig(config ant.AntConfig) (ant.AntConfig, error) {
Expand Down
6 changes: 6 additions & 0 deletions sia-antfarm/antfarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ func createAntfarm(config AntfarmConfig) (*antFarm, error) {
if err != nil {
return nil, err
}

err = startJobs(ants...)
if err != nil {
return nil, err
}

farm.ants = ants
defer func() {
if err != nil {
Expand Down