Skip to content

Commit

Permalink
Merge 203d0fc into 27747c5
Browse files Browse the repository at this point in the history
  • Loading branch information
bfbachmann committed Sep 2, 2017
2 parents 27747c5 + 203d0fc commit 2b74138
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 126 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@ vendor

# Log files
logfile

# Saved app data
user.json
blockchain.json
123 changes: 80 additions & 43 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,14 @@ var (
)

const (
// MaxBlockSize is the maximum size of a block in bytes
MaxBlockSize = 5000000
// MinBlockSize is the minimum size of a block in bytes
MinBlockSize = 1000
blockQueueSize = 100
transactionQueueSize = 100
userFileName = "user.json"
blockchainFileName = "blockchain.json"
)

// App contains information about a running instance of a Cumulus node
Expand All @@ -44,50 +50,71 @@ type App struct {
quitChan chan bool
}

// Run sets up and starts a new Cumulus node with the
// given configuration. This should only be called once (except in tests)
func Run(cfg conf.Config) {
log.Info("Starting Cumulus node")
config := &cfg

// TODO: remove this when we have scaleable difficulty
consensus.CurrentDifficulty = big.NewInt(2 << 21)

addr := fmt.Sprintf("%s:%d", config.Interface, config.Port)
user := getCurrentUser()
a := App{
PeerStore: peer.NewPeerStore(addr),
// New returns a new user with the given parameters
func New(user *User, pStore *peer.PeerStore, chain *blockchain.BlockChain, pool *pool.Pool) *App {
return &App{
PeerStore: pStore,
CurrentUser: user,
Chain: createBlockchain(user),
Chain: chain,
Miner: miner.New(),
Pool: getLocalPool(),
Pool: pool,
blockQueue: make(chan *blockchain.Block, blockQueueSize),
transactionQueue: make(chan *blockchain.Transaction, transactionQueueSize),
quitChan: make(chan bool),
}
}

// Run sets up and starts a new Cumulus node with the
// given configuration. This should only be called once (except in tests)
func Run(cfg conf.Config) {
// Set logging level
if cfg.Verbose {
log.SetLevel(log.DebugLevel)
}

log.Info("Starting Cumulus node")
config := &cfg
addr := fmt.Sprintf("%s:%d", config.Interface, config.Port)

// Set starting difficulty (TODO: remove this when we have adjustable difficulty)
consensus.CurrentDifficulty = big.NewInt(2 << 21)

// Load user info from a file (or create a new user if there isn't one on disk)
user, err := Load(userFileName)
if err != nil {
user = NewUser()
if err := user.Save(userFileName); err != nil {
log.WithError(err).Fatal("Failed to save new user info to ", userFileName)
} else {
log.Info("Saved new user info to file ", userFileName)
}
} else {
log.Info("Loaded user info from ", userFileName)
}

// Load blockchain from a file (or create a new one if there isn't one on disk)
chain, err := blockchain.Load(blockchainFileName)
if err != nil {
genesisBlock := blockchain.Genesis(user.Public(), consensus.CurrentTarget(),
consensus.StartingBlockReward, []byte{})
chain = blockchain.New()
chain.AppendBlock(genesisBlock)
log.Info("Created new blockchain with genesis block")
} else {
log.Info("Loaded blockchain from ", blockchainFileName)
}

// Create new app instance
a := New(user, peer.NewPeerStore(addr), chain, pool.New())

// We'll need to wait on at least 2 goroutines (Listen and
// MaintainConnections) to start before returning
wg := &sync.WaitGroup{}
wg.Add(2)
wg.Add(3)

// Start a goroutine that waits for program termination. Before the program
// exits it will flush logs and save the blockchain.
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
log.Info("Saving blockchain and flushing logs...")
// TODO
logFile.Sync()
logFile.Close()
os.Exit(0)
}()
go a.awaitExit(wg)

// Below we'll connect to peers. After which, requests could begin to
// stream in. Kick off a worker to handle requests and pushes.
Expand All @@ -101,7 +128,7 @@ func Run(cfg conf.Config) {

// Start listening on the given interface and port so we can receive
// conenctions from other peers
log.Infof("Starting listener on %s:%d", cfg.Interface, cfg.Port)
log.Infof("Starting listener on %s", addr)
a.PeerStore.ListenAddr = addr
go func() {
err := conn.Listen(addr, a.PeerStore.ConnectionHandler, wg)
Expand All @@ -128,20 +155,12 @@ func Run(cfg conf.Config) {
}
log.Info("Redirecting logs to logfile")
log.SetOutput(logFile)
go RunConsole(&a)
go RunConsole(a)
}

if len(config.Target) > 0 {
// Connect to the target and discover its peers.
// Connect to the target, discover its peers, and download the blockchain
a.ConnectAndDiscover(cfg.Target)

// Download blockchain
log.Info("Syncronizing blockchain")
_, err := a.SyncBlockChain()
if err != nil {
log.WithError(err).Fatal("Failed to download blockchain")
}
log.Info("Blockchain synchronization complete")
}

if config.Mine {
Expand All @@ -163,6 +182,14 @@ func (a *App) ConnectAndDiscover(target string) {
log.WithError(err).Fatal("Failed to dial target")
}
p.Request(peerInfoRequest, a.PeerStore.PeerInfoHandler)

// Download blockchain
log.Info("Syncronizing blockchain")
_, err = a.SyncBlockChain()
if err != nil {
log.WithError(err).Fatal("Failed to download blockchain")
}
log.Info("Blockchain synchronization complete")
}

// RequestHandler is called every time a peer sends us a request message expect
Expand Down Expand Up @@ -266,12 +293,6 @@ func createBlockchain(user *User) *blockchain.BlockChain {
return bc
}

// getLocalPool returns an instance of the pool.
func getLocalPool() *pool.Pool {
// TODO: Look for local pool on disk. If doesn't exist, make a new one.
return pool.New()
}

// HandleWork continually collects new work from existing work channels.
func (a *App) HandleWork() {
log.Debug("Worker waiting for work")
Expand Down Expand Up @@ -519,3 +540,19 @@ func (a *App) handleBlockResponse(newBlockChan chan *blockchain.Block,
return false, false
}
}

// awaitExit waits until the interrupt or terminate signal and cleans up before
// cumulus terminates.
func (a *App) awaitExit(wg *sync.WaitGroup) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
wg.Done()
<-c
log.Info("Saving blockchain and flushing logs...")
if err := a.Chain.Save(blockchainFileName); err != nil {
log.WithError(err).Error("Error saving blockchain")
}
logFile.Sync()
logFile.Close()
os.Exit(0)
}
Loading

0 comments on commit 2b74138

Please sign in to comment.