| 1817 | } |
| 1818 | |
| 1819 | bool CheckBlock(const CBlock &block, CValidationState &state, CCacheWrapper &cw, bool fCheckTx, bool fCheckMerkleRoot) { |
| 1820 | if (block.vptx.empty() || block.vptx.size() > MAX_BLOCK_SIZE || |
| 1821 | ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) |
| 1822 | return state.DoS(100, ERRORMSG("size limits failed"), REJECT_INVALID, "bad-blk-length"); |
| 1823 | |
| 1824 | if ((block.GetHeight() != 0 || block.GetHash() != SysCfg().GetGenesisBlockHash()) && |
| 1825 | block.GetVersion() != CBlockHeader::CURRENT_VERSION) { |
| 1826 | return state.Invalid(ERRORMSG("block version error"), REJECT_INVALID, "block-version-error"); |
| 1827 | } |
| 1828 | |
| 1829 | // Check timestamp `block interval' + 2 seconds limits |
| 1830 | if (block.GetBlockTime() > GetAdjustedTime() + ::GetBlockInterval(block.GetHeight()) + 2) |
| 1831 | return state.Invalid(ERRORMSG("block timestamp too far in the future"), REJECT_INVALID, |
| 1832 | "time-too-new"); |
| 1833 | |
| 1834 | // First transaction must be reward transaction, the rest must not be |
| 1835 | if (block.vptx.empty() || !block.vptx[0]->IsBlockRewardTx()) |
| 1836 | return state.DoS(100, ERRORMSG("first tx is not coinbase"), REJECT_INVALID, "bad-cb-missing"); |
| 1837 | |
| 1838 | // Build the merkle tree already. We need it anyway later, and it makes the |
| 1839 | // block cache the transaction hashes, which means they don't need to be |
| 1840 | // recalculated many times during this block's validation. |
| 1841 | block.BuildMerkleTree(); |
| 1842 | |
| 1843 | // Check for duplicate txids. This is caught by ConnectInputs(), |
| 1844 | // but catching it earlier avoids a potential DoS attack: |
| 1845 | set<uint256> uniqueTxSet; |
| 1846 | uint32_t priceMedianTxCount = 0; |
| 1847 | for (uint32_t i = 0; i < block.vptx.size(); i++) { |
| 1848 | uniqueTxSet.insert(block.GetTxid(i)); |
| 1849 | if (block.GetHeight() != 0 || block.GetHash() != SysCfg().GetGenesisBlockHash()) { |
| 1850 | if (i > 0 && block.vptx[i]->IsBlockRewardTx()) |
| 1851 | return state.DoS(100, ERRORMSG("more than one block reward tx"), REJECT_INVALID, |
| 1852 | "bad-block-reward-tx-multiple"); |
| 1853 | } |
| 1854 | |
| 1855 | if (block.vptx[i]->IsPriceMedianTx()) |
| 1856 | priceMedianTxCount++; |
| 1857 | } |
| 1858 | |
| 1859 | |
| 1860 | // In stable coin release, every block should have one price median tx only. |
| 1861 | if (GetFeatureForkVersion(block.GetHeight()) >= MAJOR_VER_R2 && priceMedianTxCount != 1) |
| 1862 | return state.DoS(100, ERRORMSG("price median tx number error"), REJECT_INVALID, |
| 1863 | "bad-price-median-tx-number"); |
| 1864 | |
| 1865 | if (uniqueTxSet.size() != block.vptx.size()) |
| 1866 | return state.DoS(100, ERRORMSG("duplicated trx"), REJECT_INVALID, "bad-tx-duplicated", true); |
| 1867 | |
| 1868 | // Check merkle root |
| 1869 | if (fCheckMerkleRoot && block.GetMerkleRootHash() != block.vMerkleTree.back()) |
| 1870 | return state.DoS(100, ERRORMSG("[%d] merkleRootHash mismatch: in-block: #%s vs computed: #%s", |
| 1871 | block.GetHeight(), block.GetMerkleRootHash().ToString(), block.vMerkleTree.back().ToString()), |
| 1872 | REJECT_INVALID, "bad-merkle-root", true); |
| 1873 | |
| 1874 | // Check nonce |
| 1875 | static uint64_t maxNonce = SysCfg().GetBlockMaxNonce(); |
| 1876 | if (block.GetNonce() > maxNonce) |