解锁脚本与锁定脚本的组合为:2 << 3 << OP_ADD << 5 << OP_EQUAL;即通过调用比特币相关的脚本操作完成2 + 3 == 5的验证过程。
6.1.1.1 构建锁定脚本
//构建锁定脚本
CScript scriptLock;
scriptLock << 3 << OP_ADD << 5 << OP_EQUAL;
即构建的锁定脚本为:3 << OP_ADD << 5 << OP_EQUAL;
6.1.1.2 构建解锁脚本
//构建解锁脚本
CScript scriptUnlock;
scriptUnlock << 2;
scriptUnlock = CScript() + scriptUnlock;
即构建的解锁脚本为:2;
6.1.1.3 调用evalScript函数验证脚本
//脚本验证
if(CScript().empty())
if(!evalScript(scriptUnlock + scriptLock))
return error("Bitcoin_script : evalScript failed");
OP_ADD、OP_EQUAL等脚本操作在evalScript()函数中实现。
v OP_ADD
// (x1 x2 -- out)
if (stack.size() < 2)
return false;
CBigNum bn1(stacktop(-2));
CBigNum bn2(stacktop(-1));
CBigNum bn;
bn = bn1 + bn2;
stack.pop_back();
stack.pop_back();
stack.push_back(bn.getvch());
Ø
将堆栈(后进先出)中的数据实例化为大数bn1、bn2
Ø
进行加法操作:bn = bn1 + bn2
Ø
bn1、bn2出栈,即在堆栈中删除bn1、bn2:stack.pop_back();
Ø
bn入栈,完成OP_ADD操作
v OP_EQUAL
// (x1 x2 - bool)
if (stack.size() < 2)
return false;
valtype& vch1 = stacktop(-2);
valtype& vch2 = stacktop(-1);
bool fEqual = (vch1 == vch2);
stack.pop_back();
stack.pop_back();
stack.push_back(fEqual ? vchTrue : vchFalse);
if (opcode == OP_EQUALVERIFY)
{
if (fEqual)
stack.pop_back();
else
pc = pend;
}
Ø
将堆栈(后进先出)中的数据实例化vch1、vch2
Ø
进行相等判断bool fEqual = (vch1 == vch2)
Ø
vch1、vch2出栈
Ø
判断fEqual,将结果入栈stack.push_back(fEqual ? vchTrue : vchFalse)
Ø 进行OP_EQUALVERIFY操作,如果fEqual为真,则上一步的结果出栈;如果fEqual为假,结束脚本操作,返回结果。
CTransaction txNew;
CreateTransaction(txNew, key);
6.2.2 构建交易输入
tx.vin.resize(1);
tx.vin[0].prevout.SetNull();
tx.vin[0].scriptSig << nBits << ++bnExtraNonce;
6.2.3构建交易输出
tx.vout.resize(1);
tx.vout[0].nValue = 50 * COIN;
tx.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG;
//debug print
tx.print();
return true;
}
P2PKH标准详解
CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
即锁定脚本为:OP_DUP OP_HASH160 hash160
OP_DUP:堆栈中的复制操作;
OP_HASH160:哈希160操作,得到公钥哈希(scriptPubKey)
OP_EQUALVERIFY:想等判断
OP_CHECKSIG:验证签名是否和公钥签名匹配
VerifySignature(wtxFrom, wtxNew, 0);
通过调用EvalScript()、CheckSig()函数完成验证操作。
新建交易
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, nFeeRequired))
{
string strError;
if (nValue + nFeeRequired > GetBalance())
strError = strprintf("Error: This is an oversized transaction that requires a transaction fee of %s ", FormatMoney(nFeeRequired).c_str());
else
strError = "Error: Transaction creation failed ";
wxMessageBox(strError, "Sending...");
return error("SendMoney() : %s\n", strError.c_str());
}
选取交易
具体选择交易使用的“随机逼近算法”在后续《比特币源码解读之选币》一文中介绍
set setCoins;
if (!SelectCoins(nValue, setCoins))
return false;
计算交易费
如果默认的交易费小于当前计算的交易费用,则需要根据当前计算的交易费重新填充交易
// Check that enough fee is included
if (nFee < wtxNew.GetMinFee(true))
{
nFee = nFeeRequiredRet = wtxNew.GetMinFee(true);
continue;
}
填充输入和输出
填充输出
wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey));
// Fill vout[1] back to self with any change
if (nValueIn > nValue)
{
// Use the same key as one of the coins
vector vchPubKey;
CTransaction& txFirst = *(*setCoins.begin());
foreach(const CTxOut& txout, txFirst.vout)
if (txout.IsMine())
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
break;
if (vchPubKey.empty())
return false;
// Fill vout[1] to ourself
CScript scriptPubKey;
scriptPubKey << vchPubKey << OP_CHECKSIG;
wtxNew.vout.push_back(CTxOut(nValueIn - nValue, scriptPubKey));
}
填充输入
foreach(CWalletTx* pcoin, setCoins)
for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
if (pcoin->vout[nOut].IsMine())
wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut));
签名
int nIn = 0;
foreach(CWalletTx* pcoin, setCoins)
for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
if (pcoin->vout[nOut].IsMine())
SignSignature(*pcoin, wtxNew, nIn++);
计算Merkle值
wtxNew.AddSupportingTransactions(txdb);
void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
{
vtxPrev.clear();
const int COPY_DEPTH = 3;
if (SetMerkleBranch() < COPY_DEPTH)
{
vector vWorkQueue;
foreach(const CTxIn& txin, vin)
vWorkQueue.push_back(txin.prevout.hash);
// This critsect is OK because txdb is already open
CRITICAL_BLOCK(cs_mapWallet)
{
map mapWalletPrev;
set setAlreadyDone;
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hash = vWorkQueue[i];
if (setAlreadyDone.count(hash))
continue;
setAlreadyDone.insert(hash);
CMerkleTx tx;
if (mapWallet.count(hash))
{
tx = mapWallet[hash];
foreach(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev)
mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
}
else if (mapWalletPrev.count(hash))
{
tx = *mapWalletPrev[hash];
}
else if (!fClient && txdb.ReadDiskTx(hash, tx))
{
;
}
else
{
printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
continue;
}
int nDepth = tx.SetMerkleBranch();
vtxPrev.push_back(tx);
if (nDepth < COPY_DEPTH)
foreach(const CTxIn& txin, tx.vin)
vWorkQueue.push_back(txin.prevout.hash);
}
}
}
reverse(vtxPrev.begin(), vtxPrev.end());
}
提交交易请求
if (!CommitTransactionSpent(wtxNew))
{
wxMessageBox("Error finalizing transaction", "Sending...");
return error("SendMoney() : Error finalizing transaction");
}
增加交易到钱包中
增加交易到钱包中并保存在mapWallet变量中,通过将选择交易写入磁盘
bool CommitTransactionSpent(const CWalletTx& wtxNew)
{
... ...
AddToWallet(wtxNew);
// Mark old coins as spent
set setCoins;
foreach(const CTxIn& txin, wtxNew.vin)
setCoins.insert(&mapWallet[txin.prevout.hash]);
foreach(CWalletTx* pcoin, setCoins)
{
pcoin->fSpent = true;
pcoin->WriteToDisk();
vWalletUpdated.push_back(make_pair(pcoin->GetHash(), false));
}
}
MainFrameRepaint();
return true;
}
接受交易
if (!wtxNew.AcceptTransaction())
{
// This must not fail. The transaction has already been signed and recorded.
throw runtime_error("SendMoney() : wtxNew.AcceptTransaction() failed\n");
wxMessageBox("Error: Transaction not valid", "Sending...");
return error("SendMoney() : Error: Transaction not valid");
}
检查交易是否有效
if (IsCoinBase())
return error("AcceptTransaction() : coinbase as individual tx");
if (!CheckTransaction())
return error("AcceptTransaction() : CheckTransaction failed");
检查交易是否创建成功
uint256 hash = GetHash();
CRITICAL_BLOCK(cs_mapTransactions)
if (mapTransactions.count(hash))
return false;
if (fCheckInputs)
if (txdb.ContainsTx(hash))
return false;
检查交易是否冲突
uint256 hash = GetHash();
CRITICAL_BLOCK(cs_mapTransactions)
if (mapTransactions.count(hash))
return false;
if (fCheckInputs)
if (txdb.ContainsTx(hash))
return false;
// Check for conflicts with in-memory transactions
CTransaction* ptxOld = NULL;
for (int i = 0; i < vin.size(); i++)
{
COutPoint outpoint = vin[i].prevout;
if (mapNextTx.count(outpoint))
{
// Allow replacing with a newer version of the same transaction
if (i != 0)
return false;
ptxOld = mapNextTx[outpoint].ptx;
if (!IsNewerThan(*ptxOld))
return false;
for (int i = 0; i < vin.size(); i++)
{
COutPoint outpoint = vin[i].prevout;
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
return false;
}
break;
}
}
检查是否与已有交易冲突
map mapUnused;
int64 nFees = 0;
if (fCheckInputs && !ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), 0, nFees, false, false))
{
if (pfMissingInputs)
*pfMissingInputs = true;
return error("AcceptTransaction() : ConnectInputs failed %s", hash.ToString().substr(0,6).c_str());
}
交易保存到内存中
CRITICAL_BLOCK(cs_mapTransactions)
{
if (ptxOld)
{
printf("mapTransaction.erase(%s) replacing with new version\n", ptxOld->GetHash().ToString().c_str());
mapTransactions.erase(ptxOld->GetHash());
}
AddToMemoryPool();
}
从钱包移除旧的交易
if (ptxOld)
EraseFromWallet(ptxOld->GetHash());
广播钱包中的交易
wtxNew.RelayWalletTransaction();
发送INV消息
void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
{
foreach(const CMerkleTx& tx, vtxPrev)
{
if (!tx.IsCoinBase())
{
uint256 hash = tx.GetHash();
if (!txdb.ContainsTx(hash))
RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
}
}
if (!IsCoinBase())
{
uint256 hash = GetHash();
if (!txdb.ContainsTx(hash))
{
printf("Relaying wtx %s\n", hash.ToString().substr(0,6).c_str());
RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
}
}
}