Skip to content

Commit

Permalink
all: Update for core changes, add UPnP
Browse files Browse the repository at this point in the history
  • Loading branch information
lukechampine committed Oct 21, 2023
1 parent e1f6576 commit f845008
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 46 deletions.
16 changes: 8 additions & 8 deletions api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ func TestWallet(t *testing.T) {
}

// create wallets
dbstore, tip, err := chain.NewDBStore(chain.NewMemDB(), n, genesisBlock)
dbstore, tipState, err := chain.NewDBStore(chain.NewMemDB(), n, genesisBlock)
if err != nil {
t.Fatal(err)
}
cm := chain.NewManager(dbstore, tip.State)
cm := chain.NewManager(dbstore, tipState)
wm := walletutil.NewEphemeralWalletManager(cm)
sav := wallet.NewSeedAddressVault(wallet.NewSeed(), 0, 20)
c, shutdown := runServer(cm, nil, wm)
Expand Down Expand Up @@ -179,11 +179,11 @@ func TestV2(t *testing.T) {
secondaryAddress := types.StandardUnlockHash(secondaryPrivateKey.PublicKey())

// create wallets
dbstore, tip, err := chain.NewDBStore(chain.NewMemDB(), n, genesisBlock)
dbstore, tipState, err := chain.NewDBStore(chain.NewMemDB(), n, genesisBlock)
if err != nil {
t.Fatal(err)
}
cm := chain.NewManager(dbstore, tip.State)
cm := chain.NewManager(dbstore, tipState)
wm := walletutil.NewEphemeralWalletManager(cm)
c, shutdown := runServer(cm, nil, wm)
defer shutdown()
Expand Down Expand Up @@ -383,11 +383,11 @@ func TestP2P(t *testing.T) {
secondaryAddress := types.StandardUnlockHash(secondaryPrivateKey.PublicKey())

// create wallets
dbstore1, tip, err := chain.NewDBStore(chain.NewMemDB(), n, genesisBlock)
dbstore1, tipState, err := chain.NewDBStore(chain.NewMemDB(), n, genesisBlock)
if err != nil {
t.Fatal(err)
}
cm1 := chain.NewManager(dbstore1, tip.State)
cm1 := chain.NewManager(dbstore1, tipState)
wm1 := walletutil.NewEphemeralWalletManager(cm1)
l1, err := net.Listen("tcp", ":0")
if err != nil {
Expand All @@ -413,11 +413,11 @@ func TestP2P(t *testing.T) {
t.Fatal(err)
}

dbstore2, tip, err := chain.NewDBStore(chain.NewMemDB(), n, genesisBlock)
dbstore2, tipState, err := chain.NewDBStore(chain.NewMemDB(), n, genesisBlock)
if err != nil {
t.Fatal(err)
}
cm2 := chain.NewManager(dbstore2, tip.State)
cm2 := chain.NewManager(dbstore2, tipState)
wm2 := walletutil.NewEphemeralWalletManager(cm2)
l2, err := net.Listen("tcp", ":0")
if err != nil {
Expand Down
8 changes: 5 additions & 3 deletions cmd/walletd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func check(context string, err error) {
func getAPIPassword() string {
apiPassword := os.Getenv("WALLETD_API_PASSWORD")
if apiPassword != "" {
fmt.Println("Using WALLETD_API_PASSWORD environment variable.")
fmt.Println("env: Using WALLETD_API_PASSWORD environment variable")
} else {
fmt.Print("Enter API password: ")
pw, err := term.ReadPassword(int(os.Stdin.Fd()))
Expand All @@ -61,9 +61,11 @@ func getAPIPassword() string {

func main() {
log.SetFlags(0)
gatewayAddr := flag.String("addr", "localhost:9981", "p2p address to listen on")
gatewayAddr := flag.String("addr", ":9981", "p2p address to listen on")
apiAddr := flag.String("http", "localhost:9980", "address to serve API on")
dir := flag.String("dir", ".", "directory to store node state in")
network := flag.String("network", "mainnet", "network to connect to")
upnp := flag.Bool("upnp", true, "attempt to forward ports and discover IP with UPnP")
flag.Parse()

log.Println("walletd v0.1.0")
Expand All @@ -79,7 +81,7 @@ func main() {
log.Fatal(err)
}

n, err := newNode(*gatewayAddr, *dir, true)
n, err := newNode(*gatewayAddr, *dir, *network, *upnp)
if err != nil {
log.Fatal(err)
}
Expand Down
70 changes: 57 additions & 13 deletions cmd/walletd/node.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package main

import (
"context"
"errors"
"log"
"net"
"path/filepath"
"strconv"
"time"

bolt "go.etcd.io/bbolt"
"go.sia.tech/core/chain"
"go.sia.tech/core/consensus"
"go.sia.tech/core/gateway"
"go.sia.tech/core/types"
"go.sia.tech/walletd/internal/syncerutil"
"go.sia.tech/walletd/internal/walletutil"
"go.sia.tech/walletd/syncer"
"lukechampine.com/upnp"
)

var mainnetBootstrap = []string{
Expand Down Expand Up @@ -108,6 +115,11 @@ func (db *boltDB) Cancel() {
db.tx = nil
}

func (db *boltDB) Close() error {
db.Flush()
return db.db.Close()
}

type node struct {
cm *chain.Manager
s *syncer.Syncer
Expand All @@ -116,40 +128,72 @@ type node struct {
Start func() (stop func())
}

func newNode(addr, dir string, zen bool) (*node, error) {
func newNode(addr, dir string, chainNetwork string, useUPNP bool) (*node, error) {
var network *consensus.Network
var genesisBlock types.Block
var bootstrapPeers []string
switch chainNetwork {
case "mainnet":
network, genesisBlock = chain.Mainnet()
bootstrapPeers = mainnetBootstrap
case "zen":
network, genesisBlock = chain.TestnetZen()
bootstrapPeers = zenBootstrap
default:
return nil, errors.New("invalid network: must be one of 'mainnet' or 'zen'")
}

bdb, err := bolt.Open(filepath.Join(dir, "consensus.db"), 0600, nil)
if err != nil {
log.Fatal(err)
}
network, genesisBlock := chain.Mainnet()
if zen {
network, genesisBlock = chain.TestnetZen()
}
dbstore, tip, err := chain.NewDBStore(&boltDB{db: bdb}, network, genesisBlock)
db := &boltDB{db: bdb}
dbstore, tipState, err := chain.NewDBStore(db, network, genesisBlock)
if err != nil {
return nil, err
}
cm := chain.NewManager(dbstore, tip.State)
cm := chain.NewManager(dbstore, tipState)

l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
syncerAddr := l.Addr().String()
if useUPNP {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if d, err := upnp.Discover(ctx); err != nil {
log.Println("WARN: couldn't discover UPnP device:", err)
} else {
_, portStr, _ := net.SplitHostPort(addr)
port, _ := strconv.Atoi(portStr)
if !d.IsForwarded(uint16(port), "TCP") {
if err := d.Forward(uint16(port), "TCP", "walletd"); err != nil {
log.Println("WARN: couldn't forward port:", err)
} else {
log.Println("p2p: Forwarded port", port)
}
}
if ip, err := d.ExternalIP(); err != nil {
log.Println("WARN: couldn't determine external IP:", err)
} else {
log.Println("p2p: External IP is", ip)
syncerAddr = net.JoinHostPort(ip, portStr)
}
}
}

ps, err := syncerutil.NewJSONPeerStore(filepath.Join(dir, "peers.json"))
if err != nil {
log.Fatal(err)
}
bootstrapPeers := mainnetBootstrap
if zen {
bootstrapPeers = zenBootstrap
}
for _, peer := range bootstrapPeers {
ps.AddPeer(peer)
}
header := gateway.Header{
GenesisID: genesisBlock.ID(),
UniqueID: gateway.GenerateUniqueID(),
NetAddress: l.Addr().String(),
NetAddress: syncerAddr,
}
s := syncer.New(l, cm, ps, header, syncer.WithLogger(log.Default()))

Expand All @@ -171,7 +215,7 @@ func newNode(addr, dir string, zen bool) (*node, error) {
return func() {
l.Close()
<-ch
bdb.Close()
db.Close()
}
},
}, nil
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ go 1.18

require (
go.etcd.io/bbolt v1.3.7
go.sia.tech/core v0.1.12-0.20230915021325-3ca4ff703dc6
go.sia.tech/core v0.1.12-0.20231021194448-f1e65eb9f0d0
go.sia.tech/jape v0.9.0
go.sia.tech/web/walletd v0.9.0
golang.org/x/term v0.6.0
lukechampine.com/frand v1.4.2
lukechampine.com/upnp v0.2.0
)

require (
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.sia.tech/core v0.1.12-0.20230915021325-3ca4ff703dc6 h1:WYQDfzDWBcbr9t+nnatOShOUB4aD2XSu/UGz28XdCwU=
go.sia.tech/core v0.1.12-0.20230915021325-3ca4ff703dc6/go.mod h1:D17UWSn99SEfQnEaR9G9n6Kz9+BwqMoUgZ6Cl424LsQ=
go.sia.tech/core v0.1.12-0.20231021194448-f1e65eb9f0d0 h1:2nKOKa99g9h9m3hL5UortAbmnwuwXhDcTHIhzmqBae8=
go.sia.tech/core v0.1.12-0.20231021194448-f1e65eb9f0d0/go.mod h1:3EoY+rR78w1/uGoXXVqcYdwSjSJKuEMI5bL7WROA27Q=
go.sia.tech/jape v0.9.0 h1:kWgMFqALYhLMJYOwWBgJda5ko/fi4iZzRxHRP7pp8NY=
go.sia.tech/jape v0.9.0/go.mod h1:4QqmBB+t3W7cNplXPj++ZqpoUb2PeiS66RLpXmEGap4=
go.sia.tech/mux v1.2.0 h1:ofa1Us9mdymBbGMY2XH/lSpY8itFsKIo/Aq8zwe+GHU=
Expand All @@ -30,3 +30,5 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
lukechampine.com/frand v1.4.2 h1:RzFIpOvkMXuPMBb9maa4ND4wjBn71E1Jpf8BzJHMaVw=
lukechampine.com/frand v1.4.2/go.mod h1:4S/TM2ZgrKejMcKMbeLjISpJMO+/eZ1zu3vYX9dtj3s=
lukechampine.com/upnp v0.2.0 h1:FWgYN50s8cTc5BQixLHy9uNgryw+qf3dd+oPS0I+vPQ=
lukechampine.com/upnp v0.2.0/go.mod h1:sOuF+fGSDKjpUm6QI0mfb82ScRrhj8bsqsD78O5nK1k=
40 changes: 21 additions & 19 deletions internal/walletutil/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,16 +209,6 @@ func (s *EphemeralStore) ProcessChainApplyUpdate(cau *chain.ApplyUpdate, _ bool)
events := wallet.AppliedEvents(cau.State, cau.Block, cau, s.ownsAddress)
s.events = append(s.events, events...)

// update proofs
for id, sce := range s.sces {
cau.UpdateElementProof(&sce.StateElement)
s.sces[id] = sce
}
for id, sfe := range s.sfes {
cau.UpdateElementProof(&sfe.StateElement)
s.sfes[id] = sfe
}

// add/remove outputs
cau.ForEachSiacoinElement(func(sce types.SiacoinElement, spent bool) {
if s.ownsAddress(sce.SiacoinOutput.Address) {
Expand All @@ -241,6 +231,16 @@ func (s *EphemeralStore) ProcessChainApplyUpdate(cau *chain.ApplyUpdate, _ bool)
}
})

// update proofs
for id, sce := range s.sces {
cau.UpdateElementProof(&sce.StateElement)
s.sces[id] = sce
}
for id, sfe := range s.sfes {
cau.UpdateElementProof(&sfe.StateElement)
s.sfes[id] = sfe
}

s.tip = cau.State.Index
return nil
}
Expand All @@ -254,15 +254,6 @@ func (s *EphemeralStore) ProcessChainRevertUpdate(cru *chain.RevertUpdate) error
numEvents := len(wallet.AppliedEvents(cru.State, cru.Block, cru, s.ownsAddress))
s.events = s.events[:len(s.events)-numEvents]

for id, sce := range s.sces {
cru.UpdateElementProof(&sce.StateElement)
s.sces[id] = sce
}
for id, sfe := range s.sfes {
cru.UpdateElementProof(&sfe.StateElement)
s.sfes[id] = sfe
}

cru.ForEachSiacoinElement(func(sce types.SiacoinElement, spent bool) {
if s.ownsAddress(sce.SiacoinOutput.Address) {
if !spent {
Expand All @@ -283,6 +274,17 @@ func (s *EphemeralStore) ProcessChainRevertUpdate(cru *chain.RevertUpdate) error
}
}
})

// update proofs
for id, sce := range s.sces {
cru.UpdateElementProof(&sce.StateElement)
s.sces[id] = sce
}
for id, sfe := range s.sfes {
cru.UpdateElementProof(&sfe.StateElement)
s.sfes[id] = sfe
}

s.tip = cru.State.Index
return nil
}
Expand Down

0 comments on commit f845008

Please sign in to comment.