func LocalAcceptBlock(newbl *network.BlockRcvd) (e error) { newbl.TmQueue = time.Now() bl := newbl.Block if common.FLAG.TrustAll { bl.Trusted = true } if !common.BlockChain.DoNotSync { common.BlockChain.DoNotSync = true syncNow <- true } e = common.BlockChain.CommitBlock(bl, newbl.BlockTreeNode) if e == nil { // new block accepted newbl.TmAccepted = time.Now() newbl.NonWitnessSize = len(bl.OldData) common.RecalcAverageBlockSize(false) for i := 1; i < len(bl.Txs); i++ { network.TxMined(bl.Txs[i]) kspb := 1000 * bl.Txs[i].Fee / uint64(bl.Txs[i].Size) if i == 1 || newbl.MinFeeKSPB > kspb { newbl.MinFeeKSPB = kspb } } if int64(bl.BlockTime()) > time.Now().Add(-10*time.Minute).Unix() { // Freshly mined block - do the inv and beeps... new_block_mined(bl, newbl.Conn) } common.Last.Mutex.Lock() common.Last.Time = time.Now() common.Last.Block = common.BlockChain.BlockTreeEnd if false && common.Last.Block.Height == 725676 { fmt.Println("Reached block number", common.Last.Block.Height, "- exiting...") usif.Exit_now = true } common.Last.Mutex.Unlock() } else { fmt.Println("Warning: AcceptBlock failed. If the block was valid, you may need to rebuild the unspent DB (-r)") common.Last.Mutex.Lock() common.Last.Block = common.BlockChain.BlockTreeEnd common.Last.Mutex.Unlock() // update network.LastCommitedHeader network.MutexRcv.Lock() if network.LastCommitedHeader != common.BlockChain.BlockTreeEnd { network.LastCommitedHeader = common.BlockChain.BlockTreeEnd println("LastCommitedHeader moved to", network.LastCommitedHeader.Height) } network.DiscardedBlocks[newbl.Hash.BIdx()] = true network.MutexRcv.Unlock() } return }
func HandleRpcBlock(msg *rpcapi.BlockSubmited) { network.MutexRcv.Lock() rb := network.ReceivedBlocks[msg.Block.Hash.BIdx()] network.MutexRcv.Unlock() if rb == nil { panic("Block " + msg.Block.Hash.String() + " not in ReceivedBlocks map") } rb.TmQueue = time.Now() e, _, _ := common.BlockChain.CheckBlock(msg.Block) if e == nil { e = common.BlockChain.AcceptBlock(msg.Block) rb.TmAccepted = time.Now() } if e != nil { common.CountSafe("RPCBlockError") msg.Error = e.Error() msg.Done.Done() return } common.RecalcAverageBlockSize(false) for i := 1; i < len(msg.Block.Txs); i++ { network.TxMined(msg.Block.Txs[i]) } common.CountSafe("RPCBlockOK") println("New mined block", msg.Block.Height, "accepted OK") new_block_mined(msg.Block, nil) common.Last.Mutex.Lock() common.Last.Time = time.Now() common.Last.Block = common.BlockChain.BlockTreeEnd common.Last.Mutex.Unlock() msg.Done.Done() }
func main() { var ptr *byte if unsafe.Sizeof(ptr) < 8 { fmt.Println("WARNING: Gocoin client shall be build for 64-bit arch. It will likely crash now.") } fmt.Println("Gocoin client version", gocoin.Version) runtime.GOMAXPROCS(runtime.NumCPU()) // It seems that Go does not do it by default // Disable Ctrl+C signal.Notify(killchan, os.Interrupt, os.Kill) defer func() { if r := recover(); r != nil { err, ok := r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } fmt.Println("main panic recovered:", err.Error()) fmt.Println(string(debug.Stack())) network.NetCloseAll() common.CloseBlockChain(false) peersdb.ClosePeerDB() sys.UnlockDatabaseDir() os.Exit(1) } }() common.InitConfig() if common.FLAG.VolatileUTXO { fmt.Println("WARNING! Using UTXO database in a volatile mode. Make sure to close the client properly (do not kill it!)") } if common.FLAG.TrustAll { fmt.Println("WARNING! Assuming all scripts inside new blocks to PASS. Verify the last block's hash when finished.") } host_init() // This will create the DB lock file and keep it open if common.FLAG.UndoBlocks > 0 { usif.Exit_now = true } if common.FLAG.Rescan && common.FLAG.VolatileUTXO { fmt.Println("UTXO database rebuilt complete in the volatile mode, so flush DB to disk and exit...") } else if !usif.Exit_now { common.RecalcAverageBlockSize(true) peersTick := time.Tick(5 * time.Minute) txPoolTick := time.Tick(time.Minute) netTick := time.Tick(time.Second) peersdb.Testnet = common.Testnet peersdb.ConnectOnly = common.CFG.ConnectOnly peersdb.Services = common.Services peersdb.InitPeers(common.GocoinHomeDir) if common.FLAG.UnbanAllPeers { var keys []qdb.KeyType var vals [][]byte peersdb.PeerDB.Browse(func(k qdb.KeyType, v []byte) uint32 { peer := utils.NewPeer(v) if peer.Banned != 0 { fmt.Println("Unban", peer.NetAddr.String()) peer.Banned = 0 keys = append(keys, k) vals = append(vals, peer.Bytes()) } return 0 }) for i := range keys { peersdb.PeerDB.Put(keys[i], vals[i]) } fmt.Println(len(keys), "peerts un-baned") } common.Last.Block = common.BlockChain.BlockTreeEnd common.Last.Time = time.Unix(int64(common.Last.Block.Timestamp()), 0) if common.Last.Time.After(time.Now()) { common.Last.Time = time.Now() } for k, v := range common.BlockChain.BlockIndex { network.ReceivedBlocks[k] = &network.OneReceivedBlock{TmStart: time.Unix(int64(v.Timestamp()), 0)} } network.LastCommitedHeader = common.Last.Block if common.CFG.TextUI.Enabled { go textui.MainThread() } if common.CFG.WebUI.Interface != "" { fmt.Println("Starting WebUI at", common.CFG.WebUI.Interface, "...") go webui.ServerThread(common.CFG.WebUI.Interface) } if common.CFG.RPC.Enabled { go rpcapi.StartServer(common.RPCPort()) } for !usif.Exit_now { common.CountSafe("MainThreadLoops") for retryCachedBlocks { retryCachedBlocks = retry_cached_blocks() // We have done one per loop - now do something else if pending... if len(network.NetBlocks) > 0 || len(usif.UiChannel) > 0 { break } } common.Busy("") select { case s := <-killchan: fmt.Println("Got signal:", s) usif.Exit_now = true continue case rpcbl := <-rpcapi.RpcBlocks: common.CountSafe("RPCNewBlock") common.Busy("HandleRpcBlock()") HandleRpcBlock(rpcbl) case rec := <-usif.LocksChan: common.CountSafe("MainLocks") common.Busy("LockedByRequest") rec.In.Done() rec.Out.Wait() continue case newbl := <-network.NetBlocks: common.CountSafe("MainNetBlock") common.Busy("HandleNetBlock()") HandleNetBlock(newbl) case <-syncNow: common.CountSafe("MainChainSync") common.Busy("BlockChain.Sync()") common.BlockChain.Sync() case newtx := <-network.NetTxs: common.CountSafe("MainNetTx") common.Busy("network.HandleNetTx()") network.HandleNetTx(newtx, false) case <-netTick: common.CountSafe("MainNetTick") common.Busy("network.NetworkTick()") network.NetworkTick() case cmd := <-usif.UiChannel: common.CountSafe("MainUICmd") common.Busy("UI command") cmd.Handler(cmd.Param) cmd.Done.Done() continue case <-peersTick: common.Busy("peersdb.ExpirePeers()") peersdb.ExpirePeers() case <-txPoolTick: common.Busy("network.ExpireTxs()") network.ExpireTxs() case <-time.After(time.Second / 2): common.CountSafe("MainThreadTouts") if !retryCachedBlocks { if usif.DefragUTXO { usif.Exit_now = true break } common.Busy("BlockChain.Idle()") if common.BlockChain.Idle() { common.CountSafe("ChainIdleUsed") } } continue } } network.NetCloseAll() } if usif.DefragUTXO { fmt.Println("Closing blockchain while defragmenting UTXO") } else { fmt.Println("Closing blockchain") } sta := time.Now() common.CloseBlockChain(usif.DefragUTXO) fmt.Println("Blockchain closed in", time.Now().Sub(sta).String()) peersdb.ClosePeerDB() sys.UnlockDatabaseDir() }