// DebugMsgTxString dumps a verbose message containing information about the // contents of a transaction. func DebugMsgTxString(msgTx *wire.MsgTx) string { tx := dcrutil.NewTx(msgTx) isSStx, _ := stake.IsSStx(tx) isSSGen, _ := stake.IsSSGen(tx) var sstxType []bool var sstxPkhs [][]byte var sstxAmts []int64 var sstxRules [][]bool var sstxLimits [][]uint16 if isSStx { sstxType, sstxPkhs, sstxAmts, _, sstxRules, sstxLimits = stake.GetSStxStakeOutputInfo(tx) } var buffer bytes.Buffer hash := msgTx.TxSha() str := fmt.Sprintf("Transaction hash: %v, Version %v, Locktime: %v, "+ "Expiry %v\n\n", hash, msgTx.Version, msgTx.LockTime, msgTx.Expiry) buffer.WriteString(str) str = fmt.Sprintf("==INPUTS==\nNumber of inputs: %v\n\n", len(msgTx.TxIn)) buffer.WriteString(str) for i, input := range msgTx.TxIn { str = fmt.Sprintf("Input number: %v\n", i) buffer.WriteString(str) str = fmt.Sprintf("Previous outpoint hash: %v, ", input.PreviousOutPoint.Hash) buffer.WriteString(str) str = fmt.Sprintf("Previous outpoint index: %v, ", input.PreviousOutPoint.Index) buffer.WriteString(str) str = fmt.Sprintf("Previous outpoint tree: %v \n", input.PreviousOutPoint.Tree) buffer.WriteString(str) str = fmt.Sprintf("Sequence: %v \n", input.Sequence) buffer.WriteString(str) str = fmt.Sprintf("ValueIn: %v \n", input.ValueIn) buffer.WriteString(str) str = fmt.Sprintf("BlockHeight: %v \n", input.BlockHeight) buffer.WriteString(str) str = fmt.Sprintf("BlockIndex: %v \n", input.BlockIndex) buffer.WriteString(str) str = fmt.Sprintf("Raw signature script: %x \n", input.SignatureScript) buffer.WriteString(str) sigScr, _ := txscript.DisasmString(input.SignatureScript) str = fmt.Sprintf("Disasmed signature script: %v \n\n", sigScr) buffer.WriteString(str) } str = fmt.Sprintf("==OUTPUTS==\nNumber of outputs: %v\n\n", len(msgTx.TxOut)) buffer.WriteString(str) for i, output := range msgTx.TxOut { str = fmt.Sprintf("Output number: %v\n", i) buffer.WriteString(str) coins := float64(output.Value) / 1e8 str = fmt.Sprintf("Output amount: %v atoms or %v coins\n", output.Value, coins) buffer.WriteString(str) // SStx OP_RETURNs, dump pkhs and amts committed if isSStx && i != 0 && i%2 == 1 { coins := float64(sstxAmts[i/2]) / 1e8 str = fmt.Sprintf("SStx commit amount: %v atoms or %v coins\n", sstxAmts[i/2], coins) buffer.WriteString(str) str = fmt.Sprintf("SStx commit address: %x\n", sstxPkhs[i/2]) buffer.WriteString(str) str = fmt.Sprintf("SStx address type is P2SH: %v\n", sstxType[i/2]) buffer.WriteString(str) str = fmt.Sprintf("SStx all address types is P2SH: %v\n", sstxType) buffer.WriteString(str) str = fmt.Sprintf("Voting is fee limited: %v\n", sstxLimits[i/2][0]) buffer.WriteString(str) if sstxRules[i/2][0] { str = fmt.Sprintf("Voting limit imposed: %v\n", sstxLimits[i/2][0]) buffer.WriteString(str) } str = fmt.Sprintf("Revoking is fee limited: %v\n", sstxRules[i/2][1]) buffer.WriteString(str) if sstxRules[i/2][1] { str = fmt.Sprintf("Voting limit imposed: %v\n", sstxLimits[i/2][1]) buffer.WriteString(str) } } // SSGen block/block height OP_RETURN. if isSSGen && i == 0 { blkHash, blkHeight, _ := stake.GetSSGenBlockVotedOn(tx) str = fmt.Sprintf("SSGen block hash voted on: %v, height: %v\n", blkHash, blkHeight) buffer.WriteString(str) } if isSSGen && i == 1 { vb := stake.GetSSGenVoteBits(tx) str = fmt.Sprintf("SSGen vote bits: %v\n", vb) buffer.WriteString(str) } str = fmt.Sprintf("Raw script: %x \n", output.PkScript) buffer.WriteString(str) scr, _ := txscript.DisasmString(output.PkScript) str = fmt.Sprintf("Disasmed script: %v \n\n", scr) buffer.WriteString(str) } return buffer.String() }
// maybeAcceptBlock potentially accepts a block into the memory block chain. // It performs several validation checks which depend on its position within // the block chain before adding it. The block is expected to have already gone // through ProcessBlock before calling this function with it. // // The flags modify the behavior of this function as follows: // - BFDryRun: The memory chain index will not be pruned and no accept // notification will be sent since the block is not being accepted. func (b *BlockChain) maybeAcceptBlock(block *dcrutil.Block, flags BehaviorFlags) (bool, error) { dryRun := flags&BFDryRun == BFDryRun // Get a block node for the block previous to this one. Will be nil // if this is the genesis block. prevNode, err := b.getPrevNodeFromBlock(block) if err != nil { log.Debugf("getPrevNodeFromBlock: %v", err) return false, err } // The height of this block is one more than the referenced previous // block. blockHeight := int64(0) if prevNode != nil { blockHeight = prevNode.height + 1 } block.SetHeight(blockHeight) // The block must pass all of the validation rules which depend on the // position of the block within the block chain. err = b.checkBlockContext(block, prevNode, flags) if err != nil { return false, err } // Prune block nodes which are no longer needed before creating // a new node. if !dryRun { err = b.pruneBlockNodes() if err != nil { return false, err } } // Create a new block node for the block and add it to the in-memory // block chain (could be either a side chain or the main chain). blockHeader := &block.MsgBlock().Header var voteBitsStake []uint16 for _, stx := range block.STransactions() { if is, _ := stake.IsSSGen(stx); is { vb := stake.GetSSGenVoteBits(stx) voteBitsStake = append(voteBitsStake, vb) } } newNode := newBlockNode(blockHeader, block.Sha(), blockHeight, voteBitsStake) if prevNode != nil { newNode.parent = prevNode newNode.height = blockHeight newNode.workSum.Add(prevNode.workSum, newNode.workSum) } // Connect the passed block to the chain while respecting proper chain // selection according to the chain with the most proof of work. This // also handles validation of the transaction scripts. var onMainChain bool onMainChain, err = b.connectBestChain(newNode, block, flags) if err != nil { return false, err } // Notify the caller that the new block was accepted into the block // chain. The caller would typically want to react by relaying the // inventory to other peers. if !dryRun { b.sendNotification(NTBlockAccepted, &BlockAcceptedNtfnsData{onMainChain, block}) } return onMainChain, nil }