upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp30
-rw-r--r--src/main.h2
-rw-r--r--src/rpc.cpp2
-rw-r--r--src/script.cpp31
-rw-r--r--src/script.h4
5 files changed, 60 insertions, 9 deletions
diff --git a/src/main.cpp b/src/main.cpp
index aff7bab..a7298ea 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -729,12 +729,16 @@ uint256 GetOrphanRoot(const CBlock* pblock)
729 return pblock->GetHash(); 729 return pblock->GetHash();
730} 730}
731 731
732int64 CBlock::GetBlockValue(int64 nFees) const 732int64 CBlock::GetBlockValue(int nHeight, int64 nFees) const
733{ 733{
734 int64 nSubsidy = 50 * COIN; 734 int64 nSubsidy = 50 * COIN;
735 735
736 // Subsidy is cut in half every 4 years 736 // Halve on the height of this block, never on nBestHeight. The subsidy a
737 nSubsidy >>= (nBestHeight / 210000); 737 // block is allowed to pay is a property of that block; deriving it from
738 // the validating node's own tip makes the answer depend on how far that
739 // node happens to have synced, so two nodes at different heights would
740 // disagree about the same block across a halving boundary.
741 nSubsidy >>= (nHeight / 210000);
738 742
739 return nSubsidy + nFees; 743 return nSubsidy + nFees;
740} 744}
@@ -1011,7 +1015,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
1011 return false; 1015 return false;
1012 } 1016 }
1013 1017
1014 if (vtx[0].GetValueOut() > GetBlockValue(nFees)) 1018 if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
1015 return false; 1019 return false;
1016 1020
1017 // Update block index on disk without changing it in memory. 1021 // Update block index on disk without changing it in memory.
@@ -1237,6 +1241,22 @@ bool CBlock::CheckBlock() const
1237 if (!tx.CheckTransaction()) 1241 if (!tx.CheckTransaction())
1238 return error("CheckBlock() : CheckTransaction failed"); 1242 return error("CheckBlock() : CheckTransaction failed");
1239 1243
1244 // Reject blocks carrying the same transaction twice (CVE-2012-2459).
1245 //
1246 // BuildMerkleTree duplicates the last hash when a level has an odd width,
1247 // so appending a copy of the trailing transaction(s) yields a block with
1248 // an identical merkle root -- and therefore an identical block hash -- to
1249 // a legitimate one. The forgery fails validation, the hash gets recorded
1250 // as bad, and the real block is then refused because it hashes the same.
1251 set<uint256> setTxHashes;
1252 foreach(const CTransaction& tx, vtx)
1253 {
1254 uint256 hashTx = tx.GetHash();
1255 if (setTxHashes.count(hashTx))
1256 return error("CheckBlock() : duplicate transaction in block");
1257 setTxHashes.insert(hashTx);
1258 }
1259
1240 // Check proof of work matches claimed amount (memory-hard RandomX PoW) 1260 // Check proof of work matches claimed amount (memory-hard RandomX PoW)
1241 if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit) 1261 if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)
1242 return error("CheckBlock() : nBits below minimum work"); 1262 return error("CheckBlock() : nBits below minimum work");
@@ -2803,7 +2823,7 @@ bool BitcoinMiner()
2803 } 2823 }
2804 } 2824 }
2805 pblock->nBits = nBits; 2825 pblock->nBits = nBits;
2806 pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nFees); 2826 pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nBestHeight + 1, nFees);
2807 if (LogAcceptsCategory("net")) printf("\n\nRunning BitcoinMiner with %d transactions in block\n", pblock->vtx.size()); 2827 if (LogAcceptsCategory("net")) printf("\n\nRunning BitcoinMiner with %d transactions in block\n", pblock->vtx.size());
2808 2828
2809 2829
diff --git a/src/main.h b/src/main.h
index 8bb8609..533974c 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1073,7 +1073,7 @@ public:
1073 } 1073 }
1074 1074
1075 1075
1076 int64 GetBlockValue(int64 nFees) const; 1076 int64 GetBlockValue(int nHeight, int64 nFees) const;
1077 bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex); 1077 bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
1078 bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex); 1078 bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
1079 bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions); 1079 bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions);
diff --git a/src/rpc.cpp b/src/rpc.cpp
index 1b529e8..3b2dae9 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -182,7 +182,7 @@ static bool RebuildJob()
182 } 182 }
183 } 183 }
184 184
185 block.vtx[0].vout[0].nValue = block.GetBlockValue(0); 185 block.vtx[0].vout[0].nValue = block.GetBlockValue(pindexPrev->nHeight + 1, 0);
186 block.hashPrevBlock = pindexPrev->GetBlockHash(); 186 block.hashPrevBlock = pindexPrev->GetBlockHash();
187 block.hashMerkleRoot = block.BuildMerkleTree(); 187 block.hashMerkleRoot = block.BuildMerkleTree();
188 block.nTime = max((unsigned int)(pindexPrev->GetMedianTimePast() + 1), 188 block.nTime = max((unsigned int)(pindexPrev->GetMedianTimePast() + 1),
diff --git a/src/script.cpp b/src/script.cpp
index d2111ed..44eed93 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -67,6 +67,24 @@ bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nI
67 if (!script.GetOp(pc, opcode, vchPushValue)) 67 if (!script.GetOp(pc, opcode, vchPushValue))
68 return false; 68 return false;
69 69
70 if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE)
71 return false;
72
73 // Disabled opcodes. Checked before the fExec test, so they invalidate
74 // the script even inside a branch that is never taken.
75 //
76 // These are unbounded: OP_CAT grows a stack element without limit
77 // (<x> OP_DUP OP_CAT repeated doubles it each time, so a tiny script
78 // exhausts memory), and OP_LSHIFT shifts by an attacker-supplied
79 // amount with no ceiling. Both let any transaction take down every
80 // node that validates it. Bitcoin removed the whole group for this.
81 if (opcode == OP_CAT || opcode == OP_SUBSTR || opcode == OP_LEFT ||
82 opcode == OP_RIGHT || opcode == OP_INVERT || opcode == OP_AND ||
83 opcode == OP_OR || opcode == OP_XOR || opcode == OP_2MUL ||
84 opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_DIV ||
85 opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT)
86 return false;
87
70 if (fExec && opcode <= OP_PUSHDATA4) 88 if (fExec && opcode <= OP_PUSHDATA4)
71 stack.push_back(vchPushValue); 89 stack.push_back(vchPushValue);
72 else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) 90 else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
@@ -169,9 +187,18 @@ bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nI
169 187
170 case OP_RETURN: 188 case OP_RETURN:
171 { 189 {
172 pc = pend; 190 // Must fail the script outright, never just stop executing it.
191 //
192 // scriptSig and scriptPubKey are evaluated as one concatenated
193 // script (see VerifySignature). The 0.1.0 behaviour here was
194 // "pc = pend", which jumps past everything that follows — so a
195 // scriptSig of <OP_TRUE OP_RETURN> skipped the entire
196 // scriptPubKey, including OP_CHECKSIG, and the final
197 // CastToBool(stack.back()) saw the attacker's own OP_TRUE.
198 // That let anyone spend anyone else's outputs without a
199 // signature. Bitcoin closed this in 0.3.5.
200 return false;
173 } 201 }
174 break;
175 202
176 203
177 // 204 //
diff --git a/src/script.h b/src/script.h
index d52d06b..27c1b13 100644
--- a/src/script.h
+++ b/src/script.h
@@ -4,6 +4,10 @@
4 4
5class CTransaction; 5class CTransaction;
6 6
7// Largest byte vector a script may push onto the stack. Without a ceiling,
8// script evaluation allocates whatever the transaction asks it to.
9static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;
10
7enum 11enum
8{ 12{
9 SIGHASH_ALL = 1, 13 SIGHASH_ALL = 1,