add shell spv testing mode
To try uspv, do ./lnd -spv The remote node is hardcoded in shell.go. If you aren't running a full node on localhost, specify where to connect to. Nearby nodes will be much faster but random testnet nodes on the internet should also work.
This commit is contained in:
parent
2f9fc87636
commit
624e776987
4
.gitignore
vendored
4
.gitignore
vendored
@ -37,3 +37,7 @@ test_wal/*
|
|||||||
|
|
||||||
# vim
|
# vim
|
||||||
**.swp
|
**.swp
|
||||||
|
|
||||||
|
*.hex
|
||||||
|
*.db
|
||||||
|
*.bin
|
||||||
|
@ -22,8 +22,8 @@ func RpcConnect(args []string) error {
|
|||||||
}
|
}
|
||||||
fmt.Printf("connection state: %s\n", state.String())
|
fmt.Printf("connection state: %s\n", state.String())
|
||||||
time.Sleep(time.Second * 2)
|
time.Sleep(time.Second * 2)
|
||||||
// lnClient := lnrpc.NewLightningClient(conn)
|
// lnClient := lnrpc.NewLightningClient(conn)
|
||||||
// lnClient.NewAddress(nil, nil, nil) // crashes
|
// lnClient.NewAddress(nil, nil, nil) // crashes
|
||||||
|
|
||||||
state, err = conn.State()
|
state, err = conn.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
6
lnd.go
6
lnd.go
@ -21,11 +21,17 @@ var (
|
|||||||
rpcPort = flag.Int("rpcport", 10009, "The port for the rpc server")
|
rpcPort = flag.Int("rpcport", 10009, "The port for the rpc server")
|
||||||
peerPort = flag.String("peerport", "10011", "The port to listen on for incoming p2p connections")
|
peerPort = flag.String("peerport", "10011", "The port to listen on for incoming p2p connections")
|
||||||
dataDir = flag.String("datadir", "test_wal", "The directory to store lnd's data within")
|
dataDir = flag.String("datadir", "test_wal", "The directory to store lnd's data within")
|
||||||
|
spvMode = flag.Bool("spv", false, "assert to enter spv wallet mode")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if *spvMode == true {
|
||||||
|
shell()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
listenAddr := net.JoinHostPort("", "5009")
|
listenAddr := net.JoinHostPort("", "5009")
|
||||||
profileRedirect := http.RedirectHandler("/debug/pprof",
|
profileRedirect := http.RedirectHandler("/debug/pprof",
|
||||||
|
328
shell.go
Normal file
328
shell.go
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/txscript"
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
|
"github.com/btcsuite/btcutil"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/uspv"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* this is a CLI shell for testing out LND. Right now it's only for uspv
|
||||||
|
testing. It can send and receive coins.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const (
|
||||||
|
keyFileName = "testkey.hex"
|
||||||
|
headerFileName = "headers.bin"
|
||||||
|
dbFileName = "utxo.db"
|
||||||
|
// this is my local testnet node, replace it with your own close by.
|
||||||
|
// Random internet testnet nodes usually work but sometimes don't, so
|
||||||
|
// maybe I should test against different versions out there.
|
||||||
|
SPVHostAdr = "127.0.0.1:18333"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Params = &chaincfg.TestNet3Params
|
||||||
|
SCon uspv.SPVCon // global here for now
|
||||||
|
)
|
||||||
|
|
||||||
|
func shell() {
|
||||||
|
fmt.Printf("LND spv shell v0.0\n")
|
||||||
|
fmt.Printf("Not yet well integrated, but soon.\n")
|
||||||
|
|
||||||
|
// read key file (generate if not found)
|
||||||
|
rootPriv, err := uspv.ReadKeyFileToECPriv(keyFileName, Params)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// setup TxStore first (before spvcon)
|
||||||
|
Store := uspv.NewTxStore(rootPriv, Params)
|
||||||
|
// setup spvCon
|
||||||
|
|
||||||
|
SCon, err = uspv.OpenSPV(
|
||||||
|
SPVHostAdr, headerFileName, dbFileName, &Store, Params)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tip, err := SCon.TS.GetDBSyncHeight() // ask for sync height
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if tip == 0 { // DB has never been used, set to birthday
|
||||||
|
tip = 675000 // hardcoded; later base on keyfile date?
|
||||||
|
err = SCon.TS.SetDBSyncHeight(tip)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// once we're connected, initiate headers sync
|
||||||
|
err = Hdr()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// main shell loop
|
||||||
|
for {
|
||||||
|
// setup reader with max 4K input chars
|
||||||
|
reader := bufio.NewReaderSize(os.Stdin, 4000)
|
||||||
|
fmt.Printf("LND# ") // prompt
|
||||||
|
msg, err := reader.ReadString('\n') // input finishes on enter key
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdslice := strings.Fields(msg) // chop input up on whitespace
|
||||||
|
if len(cmdslice) < 1 {
|
||||||
|
continue // no input, just prompt again
|
||||||
|
}
|
||||||
|
fmt.Printf("entered command: %s\n", msg) // immediate feedback
|
||||||
|
err = Shellparse(cmdslice)
|
||||||
|
if err != nil { // only error should be user exit
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shellparse parses user input and hands it to command functions if matching
|
||||||
|
func Shellparse(cmdslice []string) error {
|
||||||
|
var err error
|
||||||
|
var args []string
|
||||||
|
cmd := cmdslice[0]
|
||||||
|
if len(cmdslice) > 1 {
|
||||||
|
args = cmdslice[1:]
|
||||||
|
}
|
||||||
|
if cmd == "exit" || cmd == "quit" {
|
||||||
|
return fmt.Errorf("User exit")
|
||||||
|
}
|
||||||
|
|
||||||
|
// help gives you really terse help. Just a list of commands.
|
||||||
|
if cmd == "help" {
|
||||||
|
err = Help(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("help error: %s\n", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// adr generates a new address and displays it
|
||||||
|
if cmd == "adr" {
|
||||||
|
err = Adr(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("adr error: %s\n", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bal shows the current set of utxos, addresses and score
|
||||||
|
if cmd == "bal" {
|
||||||
|
err = Bal(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("bal error: %s\n", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// send sends coins to the address specified
|
||||||
|
if cmd == "send" {
|
||||||
|
err = Send(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("send error: %s\n", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Command not recognized. type help for command list.\n")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hdr asks for headers.
|
||||||
|
func Hdr() error {
|
||||||
|
if SCon.RBytes == 0 {
|
||||||
|
return fmt.Errorf("No SPV connection, can't get headers.")
|
||||||
|
}
|
||||||
|
err := SCon.AskForHeaders()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bal prints out your score.
|
||||||
|
func Bal(args []string) error {
|
||||||
|
if SCon.TS == nil {
|
||||||
|
return fmt.Errorf("Can't get balance, spv connection broken")
|
||||||
|
}
|
||||||
|
fmt.Printf(" ----- Account Balance ----- \n")
|
||||||
|
allUtxos, err := SCon.TS.GetAllUtxos()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var score int64
|
||||||
|
for i, u := range allUtxos {
|
||||||
|
fmt.Printf("\tutxo %d height %d %s key: %d amt %d\n",
|
||||||
|
i, u.AtHeight, u.Op.String(), u.KeyIdx, u.Value)
|
||||||
|
score += u.Value
|
||||||
|
}
|
||||||
|
height, _ := SCon.TS.GetDBSyncHeight()
|
||||||
|
|
||||||
|
for i, a := range SCon.TS.Adrs {
|
||||||
|
fmt.Printf("address %d %s\n", i, a.PkhAdr.String())
|
||||||
|
}
|
||||||
|
fmt.Printf("Total known utxos: %d\n", len(allUtxos))
|
||||||
|
fmt.Printf("Total spendable coin: %d\n", score)
|
||||||
|
fmt.Printf("DB sync height: %d\n", height)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adr makes a new address.
|
||||||
|
func Adr(args []string) error {
|
||||||
|
a, err := SCon.TS.NewAdr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("made new address %s, %d addresses total\n",
|
||||||
|
a.String(), len(SCon.TS.Adrs))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send sends coins.
|
||||||
|
func Send(args []string) error {
|
||||||
|
// get all utxos from the database
|
||||||
|
allUtxos, err := SCon.TS.GetAllUtxos()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var score int64 // score is the sum of all utxo amounts. highest score wins.
|
||||||
|
// add all the utxos up to get the score
|
||||||
|
for _, u := range allUtxos {
|
||||||
|
score += u.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// score is 0, cannot unlock 'send coins' acheivement
|
||||||
|
if score == 0 {
|
||||||
|
return fmt.Errorf("You don't have money. Work hard.")
|
||||||
|
}
|
||||||
|
// need args, fail
|
||||||
|
if len(args) < 2 {
|
||||||
|
return fmt.Errorf("need args: ssend amount(satoshis) address")
|
||||||
|
}
|
||||||
|
amt, err := strconv.ParseInt(args[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if amt < 1000 {
|
||||||
|
return fmt.Errorf("can't send %d, too small", amt)
|
||||||
|
}
|
||||||
|
adr, err := btcutil.DecodeAddress(args[1], SCon.TS.Param)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error parsing %s as address\t", args[1])
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("send %d to address: %s \n",
|
||||||
|
amt, adr.String())
|
||||||
|
err = SendCoins(SCon, adr, amt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendCoins does send coins, but it's very rudimentary
|
||||||
|
func SendCoins(s uspv.SPVCon, adr btcutil.Address, sendAmt int64) error {
|
||||||
|
var err error
|
||||||
|
var score int64
|
||||||
|
allUtxos, err := s.TS.GetAllUtxos()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, utxo := range allUtxos {
|
||||||
|
score += utxo.Value
|
||||||
|
}
|
||||||
|
// important rule in bitcoin, output total > input total is invalid.
|
||||||
|
if sendAmt > score {
|
||||||
|
return fmt.Errorf("trying to send %d but %d available.",
|
||||||
|
sendAmt, score)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx := wire.NewMsgTx() // make new tx
|
||||||
|
// make address script 76a914...88ac
|
||||||
|
adrScript, err := txscript.PayToAddrScript(adr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// make user specified txout and add to tx
|
||||||
|
txout := wire.NewTxOut(sendAmt, adrScript)
|
||||||
|
tx.AddTxOut(txout)
|
||||||
|
|
||||||
|
nokori := sendAmt // nokori is how much is needed on input side
|
||||||
|
for _, utxo := range allUtxos {
|
||||||
|
// generate pkscript to sign
|
||||||
|
prevPKscript, err := txscript.PayToAddrScript(
|
||||||
|
s.TS.Adrs[utxo.KeyIdx].PkhAdr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// make new input from this utxo
|
||||||
|
thisInput := wire.NewTxIn(&utxo.Op, prevPKscript)
|
||||||
|
tx.AddTxIn(thisInput)
|
||||||
|
nokori -= utxo.Value
|
||||||
|
if nokori < -10000 { // minimum overage / fee is 1K now
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// there's enough left to make a change output
|
||||||
|
if nokori < -200000 {
|
||||||
|
change, err := s.TS.NewAdr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
changeScript, err := txscript.PayToAddrScript(change)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
changeOut := wire.NewTxOut((-100000)-nokori, changeScript)
|
||||||
|
tx.AddTxOut(changeOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
// use txstore method to sign
|
||||||
|
err = s.TS.SignThis(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("tx: %s", uspv.TxToString(tx))
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
|
||||||
|
tx.Serialize(buf)
|
||||||
|
fmt.Printf("tx: %x\n", buf.Bytes())
|
||||||
|
|
||||||
|
// send it out on the wire. hope it gets there.
|
||||||
|
// we should deal with rejects. Don't yet.
|
||||||
|
err = s.PushTx(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Help(args []string) error {
|
||||||
|
fmt.Printf("commands:\n")
|
||||||
|
fmt.Printf("help adr bal send exit\n")
|
||||||
|
return nil
|
||||||
|
}
|
@ -43,8 +43,7 @@ type SPVCon struct {
|
|||||||
WBytes uint64 // total bytes written
|
WBytes uint64 // total bytes written
|
||||||
RBytes uint64 // total bytes read
|
RBytes uint64 // total bytes read
|
||||||
|
|
||||||
TS *TxStore // transaction store to write to
|
TS *TxStore // transaction store to write to
|
||||||
param *chaincfg.Params // network parameters (testnet3, testnetL)
|
|
||||||
|
|
||||||
// mBlockQueue is for keeping track of what height we've requested.
|
// mBlockQueue is for keeping track of what height we've requested.
|
||||||
mBlockQueue chan HashAndHeight
|
mBlockQueue chan HashAndHeight
|
||||||
@ -56,16 +55,17 @@ type SPVCon struct {
|
|||||||
inWaitState chan bool
|
inWaitState chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func OpenSPV(remoteNode string, hfn, tsfn string,
|
func OpenSPV(remoteNode string, hfn, dbfn string,
|
||||||
inTs *TxStore, p *chaincfg.Params) (SPVCon, error) {
|
inTs *TxStore, p *chaincfg.Params) (SPVCon, error) {
|
||||||
// create new SPVCon
|
// create new SPVCon
|
||||||
var s SPVCon
|
var s SPVCon
|
||||||
|
|
||||||
// assign network parameters to SPVCon
|
// I should really merge SPVCon and TxStore, they're basically the same
|
||||||
s.param = p
|
inTs.Param = p
|
||||||
|
s.TS = inTs // copy pointer of txstore into spvcon
|
||||||
|
|
||||||
// open header file
|
// open header file
|
||||||
err := s.openHeaderFile(headerFileName)
|
err := s.openHeaderFile(hfn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
@ -80,12 +80,10 @@ func OpenSPV(remoteNode string, hfn, tsfn string,
|
|||||||
s.localVersion = VERSION
|
s.localVersion = VERSION
|
||||||
|
|
||||||
// transaction store for this SPV connection
|
// transaction store for this SPV connection
|
||||||
inTs.Param = p
|
err = inTs.OpenDB(dbfn)
|
||||||
err = inTs.OpenDB(tsfn)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
s.TS = inTs // copy pointer of txstore into spvcon
|
|
||||||
|
|
||||||
myMsgVer, err := wire.NewMsgVersionFromConn(s.con, 0, 0)
|
myMsgVer, err := wire.NewMsgVersionFromConn(s.con, 0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -99,7 +97,7 @@ func OpenSPV(remoteNode string, hfn, tsfn string,
|
|||||||
myMsgVer.AddService(wire.SFNodeBloom)
|
myMsgVer.AddService(wire.SFNodeBloom)
|
||||||
|
|
||||||
// this actually sends
|
// this actually sends
|
||||||
n, err := wire.WriteMessageN(s.con, myMsgVer, s.localVersion, s.param.Net)
|
n, err := wire.WriteMessageN(s.con, myMsgVer, s.localVersion, s.TS.Param.Net)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
@ -107,7 +105,7 @@ func OpenSPV(remoteNode string, hfn, tsfn string,
|
|||||||
log.Printf("wrote %d byte version message to %s\n",
|
log.Printf("wrote %d byte version message to %s\n",
|
||||||
n, s.con.RemoteAddr().String())
|
n, s.con.RemoteAddr().String())
|
||||||
|
|
||||||
n, m, b, err := wire.ReadMessageN(s.con, s.localVersion, s.param.Net)
|
n, m, b, err := wire.ReadMessageN(s.con, s.localVersion, s.TS.Param.Net)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
@ -126,7 +124,7 @@ func OpenSPV(remoteNode string, hfn, tsfn string,
|
|||||||
s.remoteHeight = mv.LastBlock
|
s.remoteHeight = mv.LastBlock
|
||||||
|
|
||||||
mva := wire.NewMsgVerAck()
|
mva := wire.NewMsgVerAck()
|
||||||
n, err = wire.WriteMessageN(s.con, mva, s.localVersion, s.param.Net)
|
n, err = wire.WriteMessageN(s.con, mva, s.localVersion, s.TS.Param.Net)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
@ -149,7 +147,7 @@ func (s *SPVCon) openHeaderFile(hfn string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
err = s.param.GenesisBlock.Header.Serialize(&b)
|
err = s.TS.Param.GenesisBlock.Header.Serialize(&b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -405,7 +403,7 @@ func (s *SPVCon) IngestHeaders(m *wire.MsgHeaders) (bool, error) {
|
|||||||
// advance chain tip
|
// advance chain tip
|
||||||
tip++
|
tip++
|
||||||
// check last header
|
// check last header
|
||||||
worked := CheckHeader(s.headerFile, tip, s.param)
|
worked := CheckHeader(s.headerFile, tip, s.TS.Param)
|
||||||
if !worked {
|
if !worked {
|
||||||
if endPos < 8080 {
|
if endPos < 8080 {
|
||||||
// jeez I give up, back to genesis
|
// jeez I give up, back to genesis
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
func (s *SPVCon) incomingMessageHandler() {
|
func (s *SPVCon) incomingMessageHandler() {
|
||||||
for {
|
for {
|
||||||
n, xm, _, err := wire.ReadMessageN(s.con, s.localVersion, s.param.Net)
|
n, xm, _, err := wire.ReadMessageN(s.con, s.localVersion, s.TS.Param.Net)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ReadMessageN error. Disconnecting: %s\n", err.Error())
|
log.Printf("ReadMessageN error. Disconnecting: %s\n", err.Error())
|
||||||
return
|
return
|
||||||
@ -64,7 +64,7 @@ func (s *SPVCon) incomingMessageHandler() {
|
|||||||
func (s *SPVCon) outgoingMessageHandler() {
|
func (s *SPVCon) outgoingMessageHandler() {
|
||||||
for {
|
for {
|
||||||
msg := <-s.outMsgQueue
|
msg := <-s.outMsgQueue
|
||||||
n, err := wire.WriteMessageN(s.con, msg, s.localVersion, s.param.Net)
|
n, err := wire.WriteMessageN(s.con, msg, s.localVersion, s.TS.Param.Net)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Write message error: %s", err.Error())
|
log.Printf("Write message error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,8 @@ type TxStore struct {
|
|||||||
|
|
||||||
Adrs []MyAdr // endeavouring to acquire capital
|
Adrs []MyAdr // endeavouring to acquire capital
|
||||||
StateDB *bolt.DB // place to write all this down
|
StateDB *bolt.DB // place to write all this down
|
||||||
// this is redundant with the SPVCon param... ugly and should be taken out
|
|
||||||
|
// Params live here, not SCon
|
||||||
Param *chaincfg.Params // network parameters (testnet3, testnetL)
|
Param *chaincfg.Params // network parameters (testnet3, testnetL)
|
||||||
|
|
||||||
// From here, comes everything. It's a secret to everybody.
|
// From here, comes everything. It's a secret to everybody.
|
||||||
@ -52,9 +53,10 @@ type MyAdr struct { // an address I have the private key for
|
|||||||
// inside the Adrs slice, right? leave for now
|
// inside the Adrs slice, right? leave for now
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTxStore(rootkey *hdkeychain.ExtendedKey) TxStore {
|
func NewTxStore(rootkey *hdkeychain.ExtendedKey, p *chaincfg.Params) TxStore {
|
||||||
var txs TxStore
|
var txs TxStore
|
||||||
txs.rootPrivKey = rootkey
|
txs.rootPrivKey = rootkey
|
||||||
|
txs.Param = p
|
||||||
txs.OKTxids = make(map[wire.ShaHash]int32)
|
txs.OKTxids = make(map[wire.ShaHash]int32)
|
||||||
return txs
|
return txs
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user