func checkBlock(client *btcrpcclient.Client, blockNum int64) { blockHash, err := client.GetBlockHash(653895) if err != nil { logger.Crit(err.Error()) return } block, err := client.GetBlock(blockHash) if err != nil { logger.Crit(err.Error()) return } txs := block.Transactions() var processedBlock = &message.ProcessedBlock{make([]*message.ProcessedTx, len(txs))} logger.Info("Processing txs...") for txIndex, tx := range txs { vouts := tx.MsgTx().TxOut result := make([]*message.TxResult, len(vouts)) for i, vout := range vouts { addr := NewAddrFromPkScript(vout.PkScript, true) if addr != nil { result[i] = &message.TxResult{ &message.TxResult_Transfer{ &message.ValueTransfer{ addr.String(), int32(vout.Value), }, }, } } else { result[i] = &message.TxResult{ &message.TxResult_Msg{ &message.OpReturnMsg{string(decodePkScript(vout.PkScript))}, }, } } } processedBlock.Txs[txIndex] = &message.ProcessedTx{ tx.Sha().String(), result, } } spew.Dump(processedBlock) data, err := proto.Marshal(processedBlock) if err != nil { logger.Crit(err.Error()) } else { logger.Info("Publish to ZMQ...") spew.Dump(sender) sender.SendBytes(data, 0) } logger.Info("Process done.") }
// poolUtxos receives a new block notification from the node server // and pools the newly mined utxos to the corresponding actor's a.utxo func (com *Communication) poolUtxos(client *rpc.Client, actors []*Actor) { defer com.wg.Done() // Update utxo pool on each block connected for { select { case b, ok := <-com.blockQueue.dequeue: if !ok { return } block, err := client.GetBlock(b.hash) if err != nil { log.Printf("Cannot get block: %v", err) return } // add new outputs to unspent pool for i, tx := range block.Transactions() { next: for n, vout := range tx.MsgTx().TxOut { if i == 0 { // in case of coinbase tx, add it to coinbase queue // if the chan is full, the first tx would be mature // so add it to the pool select { case com.coinbaseQueue <- tx: break next default: // dequeue the first mature tx mTx := <-com.coinbaseQueue // enqueue the latest tx com.coinbaseQueue <- tx // we'll process the mature tx next // so point tx to mTx tx = mTx // reset vout as per the new tx vout = tx.MsgTx().TxOut[n] } } // fetch actor who owns this output var actor *Actor if len(actors) == 1 { actor = actors[0] } else { actor, err = com.getActor(actors, vout) if err != nil { log.Printf("Cannot get actor: %v", err) continue next } } txout := com.getUtxo(tx, vout, uint32(n)) // to be usable, the utxo amount should be // split-able after deducting the fee if txout.Amount > btcutil.Amount((*maxSplit))*(minFee) { // if it's usable, add utxo to actor's pool select { case actor.utxoQueue.enqueue <- txout: case <-com.exit: } } } } // allow Communicate to sync with the processed block if b.height == int32(*startBlock)-1 { select { case com.blockQueue.processed <- b: case <-com.exit: return } } if b.height >= int32(*startBlock) { var txCount, utxoCount int for _, a := range actors { utxoCount += len(a.utxoQueue.utxos) } txCount = len(block.Transactions()) log.Printf("Block %s (height %d) attached with %d transactions", b.hash, b.height, txCount) log.Printf("%d transaction outputs available to spend", utxoCount) select { case com.blockQueue.processed <- b: case <-com.exit: return } select { case com.blockTxCount <- txCount: case <-com.exit: return } } case <-com.exit: return } } }
func checkBlock(client *btcrpcclient.Client, blockNum int64) { blockHash, err := client.GetBlockHash(blockNum) if err != nil { logger.Crit(err.Error()) return } block, err := client.GetBlock(blockHash) if err != nil { logger.Crit(err.Error()) return } txs := block.Transactions() var processedBlock = &message.ProcessedBlock{ int32(blockNum), make([]*message.ProcessedTx, 0), } logger.Info("Processing txs...") start := time.Now() var wg sync.WaitGroup for txIndex, tx := range txs { wg.Add(1) go func(txIndex int, tx *btcutil.Tx) { defer wg.Done() vouts := tx.MsgTx().TxOut result := make([]*message.TxResult, len(vouts)) hasReturn := false for i, vout := range vouts { btcAddr := addr.NewAddrFromPkScript(vout.PkScript, isTestnet) if btcAddr != nil { result[i] = &message.TxResult{ &message.TxResult_Transfer{ &message.ValueTransfer{ btcAddr.String(), uint64(vout.Value), }, }, } } else { msg := decodePkScript(vout.PkScript) if msg != nil { result[i] = &message.TxResult{ &message.TxResult_Msg{ &message.OpReturnMsg{string(msg)}, }, } hasReturn = true } } } if hasReturn { processedBlock.Txs = append(processedBlock.Txs, &message.ProcessedTx{ tx.Sha().String(), result, }) } }(txIndex, tx) } wg.Wait() spew.Dump(processedBlock) data, err := proto.Marshal(processedBlock) if err != nil { logger.Crit(err.Error()) } else { logger.Info("Publish to ZMQ...") spew.Dump(data) sender.SendBytes(data, 0) } elapsed := time.Since(start) logger.Info(fmt.Sprintf("Process done in %s", elapsed)) logger.Info(fmt.Sprintf("Block %d has %d OP_Return Txs", blockNum, len(processedBlock.Txs))) }