func verify_block(blk []byte, sl one_idx_rec, off int) { bl, er := btc.NewBlock(blk) if er != nil { println("verify_block at off", off, er.Error()) return } if !bytes.Equal(bl.Hash.Hash[:], sl.Hash()) { println("verify_block at off", off, "Header invalid") return } er = bl.BuildTxList() if er != nil { println("verify_block at off", off, er.Error()) return } merk, _ := btc.GetMerkle(bl.Txs) if !bytes.Equal(bl.MerkleRoot(), merk) { println("verify_block at off", off, "Payload invalid") return } }
func (ch *Chain) PostCheckBlock(bl *btc.Block) (er error) { // Size limits if len(bl.Raw) < 81 { er = errors.New("CheckBlock() : size limits failed low - RPC_Result:bad-blk-length") return } if bl.Txs == nil { er = bl.BuildTxList() if er != nil { return } if len(bl.OldData) > btc.MAX_BLOCK_SIZE { er = errors.New("CheckBlock() : size limits failed high - RPC_Result:bad-blk-length") return } } if !bl.Trusted { // We need to be satoshi compatible if len(bl.Txs) == 0 || !bl.Txs[0].IsCoinBase() { er = errors.New("CheckBlock() : first tx is not coinbase: " + bl.Hash.String() + " - RPC_Result:bad-cb-missing") return } // Enforce rule that the coinbase starts with serialized block height if bl.Height >= ch.Consensus.BIP34Height { var exp [6]byte var exp_len int binary.LittleEndian.PutUint32(exp[1:5], bl.Height) for exp_len = 5; exp_len > 1; exp_len-- { if exp[exp_len] != 0 || exp[exp_len-1] >= 0x80 { break } } exp[0] = byte(exp_len) exp_len++ if !bytes.HasPrefix(bl.Txs[0].TxIn[0].ScriptSig, exp[:exp_len]) { er = errors.New("CheckBlock() : Unexpected block number in coinbase: " + bl.Hash.String() + " - RPC_Result:bad-cb-height") return } } // And again... for i := 1; i < len(bl.Txs); i++ { if bl.Txs[i].IsCoinBase() { er = errors.New("CheckBlock() : more than one coinbase: " + bl.Hash.String() + " - RPC_Result:bad-cb-multiple") return } } // Check Merkle Root - that's importnant merkle, mutated := btc.GetMerkle(bl.Txs) if mutated { er = errors.New("CheckBlock(): duplicate transaction - RPC_Result:bad-txns-duplicate") return } if !bytes.Equal(merkle, bl.MerkleRoot()) { er = errors.New("CheckBlock() : Merkle Root mismatch - RPC_Result:bad-txnmrklroot") return } } if bl.BlockTime() >= BIP16SwitchTime { bl.VerifyFlags = script.VER_P2SH } else { bl.VerifyFlags = 0 } if bl.Height >= ch.Consensus.BIP66Height { bl.VerifyFlags |= script.VER_DERSIG } if bl.Height >= ch.Consensus.BIP65Height { bl.VerifyFlags |= script.VER_CLTV } if ch.Consensus.Enforce_CSV != 0 && bl.Height >= ch.Consensus.Enforce_CSV { bl.VerifyFlags |= script.VER_CSV } if ch.Consensus.Enforce_SEGWIT != 0 && bl.Height >= ch.Consensus.Enforce_SEGWIT { bl.VerifyFlags |= script.VER_WITNESS | script.VER_NULLDUMMY } if !bl.Trusted { var blockTime uint32 var had_witness bool if (bl.VerifyFlags & script.VER_CSV) != 0 { blockTime = bl.MedianPastTime } else { blockTime = bl.BlockTime() } // Verify merkle root of witness data if (bl.VerifyFlags & script.VER_WITNESS) != 0 { var i int for i = len(bl.Txs[0].TxOut) - 1; i >= 0; i-- { o := bl.Txs[0].TxOut[i] if len(o.Pk_script) >= 38 && bytes.Equal(o.Pk_script[:6], []byte{0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed}) { if len(bl.Txs[0].SegWit) != 1 || len(bl.Txs[0].SegWit[0]) != 1 || len(bl.Txs[0].SegWit[0][0]) != 32 { er = errors.New("CheckBlock() : invalid witness nonce size - RPC_Result:bad-witness-nonce-size") println(er.Error()) println(bl.Hash.String(), len(bl.Txs[0].SegWit)) return } // The malleation check is ignored; as the transaction tree itself // already does not permit it, it is impossible to trigger in the // witness tree. merkle, _ := btc.GetWitnessMerkle(bl.Txs) with_nonce := btc.Sha2Sum(append(merkle, bl.Txs[0].SegWit[0][0]...)) if !bytes.Equal(with_nonce[:], o.Pk_script[6:38]) { er = errors.New("CheckBlock(): Witness Merkle mismatch - RPC_Result:bad-witness-merkle-match") return } had_witness = true break } } } if !had_witness { for _, t := range bl.Txs { if t.SegWit != nil { er = errors.New("CheckBlock(): unexpected witness data found - RPC_Result:unexpected-witness") return } } } // Check transactions - this is the most time consuming task if !CheckTransactions(bl.Txs, bl.Height, blockTime) { er = errors.New("CheckBlock() : CheckTransactions() failed - RPC_Result:bad-tx") return } } return }