ethereum - build unstoppable applications
智能合約
以太坊的智能合約具有動(dòng)態(tài)腳本一樣澈侠,它可以動(dòng)態(tài)的執(zhí)行,當(dāng)我們?cè)谝蕴簧习l(fā)布了智能合約時(shí)乱顾,我們會(huì)知道發(fā)布的智能合約的地址,根據(jù)這個(gè)地址以及它定義的調(diào)用規(guī)范我們就可以調(diào)用這個(gè)合約三圆,非常方便谁撼。
同樣的我們也是通過(guò)幾個(gè)問(wèn)題來(lái)分析下智能合約的實(shí)現(xiàn),
- 智能合約在什么時(shí)候執(zhí)行的兵罢?
- 智能合約如何執(zhí)行的献烦?
智能合約在什么時(shí)候執(zhí)行的
智能合約的執(zhí)行應(yīng)該有兩種情況,一個(gè)是本節(jié)點(diǎn)通過(guò)json rpc收到transaction卖词,另外一種是收到其他節(jié)點(diǎn)傳播過(guò)來(lái)的transaction
- json rpc收到transaction
需要說(shuō)明的是,ethereumj并沒(méi)有實(shí)現(xiàn)json rpc server吏夯,不過(guò)提供了接口的實(shí)現(xiàn)此蜈,其中一個(gè)接口就是eth_sendTransaction,這個(gè)方法將收到的參數(shù)封裝成transaction噪生,再調(diào)用Ethereum的submitTransaction方法提交裆赵,后續(xù)做的事情就是合約的執(zhí)行和繼續(xù)傳播了
@Override
public Future<Transaction> submitTransaction(Transaction transaction) {
#繼續(xù)傳播的任務(wù)
TransactionTask transactionTask = new TransactionTask(transaction, channelManager);
final Future<List<Transaction>> listFuture =
TransactionExecutor.instance.submitTransaction(transactionTask);
#transaction執(zhí)行
pendingState.addPendingTransaction(transaction);
return new FutureAdapter<Transaction, List<Transaction>>(listFuture) {
@Override
protected Transaction adapt(List<Transaction> adapteeResult) throws ExecutionException {
return adapteeResult.get(0);
}
};
}
- 節(jié)點(diǎn)傳播過(guò)來(lái)的transaction
本節(jié)點(diǎn)收到其他節(jié)點(diǎn)傳播過(guò)來(lái)的transaction后,使用processTransactions處理跺嗽,如下
protected synchronized void processTransactions(TransactionsMessage msg) {
if(!processTransactions) {
return;
}
List<Transaction> txSet = msg.getTransactions();
#transaction執(zhí)行
List<Transaction> newPending = pendingState.addPendingTransactions(txSet);
if (!newPending.isEmpty()) {
TransactionTask transactionTask = new TransactionTask(newPending, channel.getChannelManager(), channel);
#繼續(xù)傳播的任務(wù) TransactionExecutor.instance.submitTransaction(transactionTask);
}
}
智能合約如何執(zhí)行的
通過(guò)上面的分析我們已經(jīng)知道合約的執(zhí)行點(diǎn)战授,具體智能合約的執(zhí)行那就應(yīng)該在addPendingTransactions方法中页藻,這個(gè)方法會(huì)循環(huán)驗(yàn)證所有的transaction,開(kāi)始執(zhí)行transaction
private boolean addPendingTransactionImpl(final Transaction tx) {
TransactionReceipt newReceipt = new TransactionReceipt();
newReceipt.setTransaction(tx);
String err = validate(tx);
TransactionReceipt txReceipt;
if (err != null) {
txReceipt = createDroppedReceipt(tx, err);
} else {
#執(zhí)行transaction植兰,下面分析
txReceipt = executeTx(tx);
}
if (!txReceipt.isValid()) {
fireTxUpdate(txReceipt, DROPPED, getBestBlock());
} else {
pendingTransactions.add(new PendingTransaction(tx, getBestBlock().getNumber()));
fireTxUpdate(txReceipt, NEW_PENDING, getBestBlock());
}
return txReceipt.isValid();
}
executeTx代碼如下:
private TransactionReceipt executeTx(Transaction tx) {
logger.trace("Apply pending state tx: {}", Hex.toHexString(tx.getHash()));
Block best = getBestBlock();
TransactionExecutor executor = new TransactionExecutor(
tx, best.getCoinbase(), getRepository(),
blockStore, programInvokeFactory, createFakePendingBlock(), new EthereumListenerAdapter(), 0)
.withCommonConfig(commonConfig);
#驗(yàn)證gas是否足夠份帐,是否超出限值,nonce是否有效等楣导,這些通過(guò)之后废境,readyToExecute設(shè)置為true
executor.init();
# 合約沒(méi)有創(chuàng)建過(guò)則創(chuàng)建否則初始化vm以及program
executor.execute();
# 執(zhí)行合約,如何執(zhí)行的筒繁,下面分析
executor.go();
executor.finalization();
return executor.getReceipt();
}
executor.execute()方法初始化了vm以及program噩凹,在program中封裝了合約代碼
#合約代碼所在的位置
byte[] code = track.getCode(targetAddress);
if (isEmpty(code)) {
m_endGas = m_endGas.subtract(BigInteger.valueOf(basicTxCost));
result.spendGas(basicTxCost);
} else {
ProgramInvoke programInvoke =
programInvokeFactory.createProgramInvoke(tx, currentBlock, cacheTrack, blockStore);
this.vm = new VM(config);
this.program = new Program(track.getCodeHash(targetAddress), code, programInvoke, tx, config).withCommonConfig(commonConfig);
}
executor.go()中通過(guò)解析code中的操作符,執(zhí)行相應(yīng)的操作毡咏,比如在智能合約中可以拿到COINBASE驮宴,那么在操作符中有相應(yīng)的處理:
case COINBASE: {
DataWord coinbase = program.getCoinbase();
if (logger.isInfoEnabled())
hint = "coinbase: " + Hex.toHexString(coinbase.getLast20Bytes());
program.stackPush(coinbase);
program.step();
}
這些都是vm去實(shí)現(xiàn)的