diff --git a/aion_fastvm b/aion_fastvm index 030194085d..292e6289ba 160000 --- a/aion_fastvm +++ b/aion_fastvm @@ -1 +1 @@ -Subproject commit 030194085d7badaeb0c3a4b80c6d45e4fd57d405 +Subproject commit 292e6289ba39f939bb6d67f8c28493fa2208a671 diff --git a/aion_vm_api b/aion_vm_api index bc69a03943..bcca6a8bcf 160000 --- a/aion_vm_api +++ b/aion_vm_api @@ -1 +1 @@ -Subproject commit bc69a039432f6a4d7771273d7381725699814514 +Subproject commit bcca6a8bcf43124b0579bd3a901f1a21e65e106d diff --git a/lib/org-aion-avm-api.jar b/lib/org-aion-avm-api.jar index 0c35b35870..e0ffbb0fc3 100644 Binary files a/lib/org-aion-avm-api.jar and b/lib/org-aion-avm-api.jar differ diff --git a/lib/org-aion-avm-core.jar b/lib/org-aion-avm-core.jar index c2b0d630ca..71eb4bbdf1 100644 Binary files a/lib/org-aion-avm-core.jar and b/lib/org-aion-avm-core.jar differ diff --git a/lib/org-aion-avm-rt.jar b/lib/org-aion-avm-rt.jar index a7c0706015..50705979d4 100644 Binary files a/lib/org-aion-avm-rt.jar and b/lib/org-aion-avm-rt.jar differ diff --git a/lib/org-aion-avm-userlib.jar b/lib/org-aion-avm-userlib.jar index ede0bcf612..262d2a8478 100644 Binary files a/lib/org-aion-avm-userlib.jar and b/lib/org-aion-avm-userlib.jar differ diff --git a/modAion/src/org/aion/zero/types/AionTransaction.java b/modAion/src/org/aion/zero/types/AionTransaction.java index c77fb56c46..2b2a154547 100644 --- a/modAion/src/org/aion/zero/types/AionTransaction.java +++ b/modAion/src/org/aion/zero/types/AionTransaction.java @@ -31,6 +31,9 @@ public class AionTransaction extends AbstractTransaction { RLP_TX_TYPE = 7, RLP_TX_SIG = 8; + public static byte CALL_KIND = 0; + public static byte CREATE_KIND = 3; + /* Tx in encoded form */ protected byte[] rlpEncoded; @@ -514,6 +517,11 @@ public long getTransactionCost() { return transactionCost(0); } + @Override + public byte getKind() { + return this.isContractCreationTransaction() ? CREATE_KIND : CALL_KIND; + } + public long transactionCost(long blockNumber) { long nonZeroes = nonZeroBytesInData(); long zeroes = zeroBytesInData(); diff --git a/modAionImpl/test/org/aion/zero/impl/PendingStateTest.java b/modAionImpl/test/org/aion/zero/impl/PendingStateTest.java index 3e4785922e..e712fc2c8c 100644 --- a/modAionImpl/test/org/aion/zero/impl/PendingStateTest.java +++ b/modAionImpl/test/org/aion/zero/impl/PendingStateTest.java @@ -67,7 +67,7 @@ public void testAddPendingTransactionSuccess() { new AionTransaction( BigInteger.ZERO.toByteArray(), to, - new byte[0], + BigInteger.ZERO.toByteArray(), new byte[0], 1_000_000L, 10_000_000_000L); @@ -100,7 +100,7 @@ public void testAddPendingTransactionInvalidNrgPrice() { new AionTransaction( BigInteger.ZERO.toByteArray(), to, - new byte[0], + BigInteger.ZERO.toByteArray(), new byte[0], 1_000_000L, 1L); diff --git a/modMcf/src/org/aion/mcf/vm/types/KernelInterfaceForFastVM.java b/modMcf/src/org/aion/mcf/vm/types/KernelInterfaceForFastVM.java index 9f9a816b19..39cac81377 100644 --- a/modMcf/src/org/aion/mcf/vm/types/KernelInterfaceForFastVM.java +++ b/modMcf/src/org/aion/mcf/vm/types/KernelInterfaceForFastVM.java @@ -5,6 +5,7 @@ import com.google.common.annotations.VisibleForTesting; import java.math.BigInteger; import org.aion.interfaces.db.RepositoryCache; +import org.aion.interfaces.vm.DataWord; import org.aion.mcf.core.AccountState; import org.aion.mcf.db.IBlockStoreBase; import org.aion.mcf.tx.TransactionTypes; @@ -23,16 +24,40 @@ public class KernelInterfaceForFastVM implements KernelInterface { public KernelInterfaceForFastVM( RepositoryCache> repositoryCache, boolean allowNonceIncrement, - boolean isLocalCall) { - - this(repositoryCache, allowNonceIncrement, isLocalCall, false); - } + boolean isLocalCall, + DataWord blockDifficulty, + long blockNumber, + long blockTimestamp, + long blockNrgLimit, + Address blockCoinbase) { + this( + repositoryCache, + allowNonceIncrement, + isLocalCall, + false, + blockDifficulty, + blockNumber, + blockTimestamp, + blockNrgLimit, + blockCoinbase); + } + + private DataWord blockDifficulty; + private long blockNumber; + private long blockTimestamp; + private long blockNrgLimit; + private Address blockCoinbase; public KernelInterfaceForFastVM( RepositoryCache> repositoryCache, boolean allowNonceIncrement, boolean isLocalCall, - boolean fork040Enable) { + boolean fork040Enable, + DataWord blockDifficulty, + long blockNumber, + long blockTimestamp, + long blockNrgLimit, + Address blockCoinbase) { if (repositoryCache == null) { throw new NullPointerException("Cannot set null repositoryCache!"); @@ -41,6 +66,11 @@ public KernelInterfaceForFastVM( this.allowNonceIncrement = allowNonceIncrement; this.isLocalCall = isLocalCall; this.fork040Enable = fork040Enable; + this.blockDifficulty = blockDifficulty; + this.blockNumber = blockNumber; + this.blockTimestamp = blockTimestamp; + this.blockNrgLimit = blockNrgLimit; + this.blockCoinbase = blockCoinbase; } @Override @@ -49,7 +79,12 @@ public KernelInterfaceForFastVM makeChildKernelInterface() { this.repositoryCache.startTracking(), this.allowNonceIncrement, this.isLocalCall, - this.fork040Enable); + this.fork040Enable, + this.blockDifficulty, + this.blockNumber, + this.blockTimestamp, + this.blockNrgLimit, + this.blockCoinbase); } @Override @@ -302,4 +337,33 @@ private ByteArrayWrapper alignDataToWordSize(byte[] data) { public boolean isFork040Enable() { return this.fork040Enable; } + + @Override + public long getBlockNumber() { + return blockNumber; + } + + @Override + public long getBlockTimestamp() { + return blockTimestamp; + } + + @Override + public long getBlockEnergyLimit() { + return blockNrgLimit; + } + + @Override + public long getBlockDifficulty() { + if (blockDifficulty instanceof DataWordImpl) { + return ((DataWordImpl) blockDifficulty).longValue(); + } else { + return ((DoubleDataWord) blockDifficulty).longValue(); + } + } + + @Override + public Address getMinerAddress() { + return blockCoinbase; + } } diff --git a/modPrecompiled/src/org/aion/precompiled/PrecompiledTransactionResult.java b/modPrecompiled/src/org/aion/precompiled/PrecompiledTransactionResult.java index a9f8ebc94c..127550f6fa 100644 --- a/modPrecompiled/src/org/aion/precompiled/PrecompiledTransactionResult.java +++ b/modPrecompiled/src/org/aion/precompiled/PrecompiledTransactionResult.java @@ -2,10 +2,19 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.aion.types.Address; +import org.aion.vm.api.interfaces.IExecutionLog; +import org.aion.vm.api.interfaces.InternalTransactionInterface; import org.aion.vm.api.interfaces.KernelInterface; import org.aion.vm.api.interfaces.ResultCode; import org.aion.vm.api.interfaces.TransactionResult; import org.aion.util.bytes.ByteUtil; +import org.aion.vm.api.interfaces.TransactionSideEffects; public class PrecompiledTransactionResult implements TransactionResult { private KernelInterface kernel; @@ -152,6 +161,87 @@ public KernelInterface getKernelInterface() { return this.kernel; } + @Override + public TransactionSideEffects getSideEffects() { + return new TransactionSideEffects() { + + private Set
deleteAccounts = new HashSet<>(); + private List internalTxs = new ArrayList<>(); + private List logs = new ArrayList<>(); + + @Override + public void merge(TransactionSideEffects other) { + addInternalTransactions(other.getInternalTransactions()); + addAllToDeletedAddresses(other.getAddressesToBeDeleted()); + addLogs(other.getExecutionLogs()); + } + + @Override + public void markAllInternalTransactionsAsRejected() { + for (InternalTransactionInterface tx : getInternalTransactions()) { + tx.markAsRejected(); + } + } + + @Override + public void addInternalTransaction(InternalTransactionInterface tx) { + internalTxs.add(tx); + } + + @Override + public void addInternalTransactions(List txs) { + for (InternalTransactionInterface tx : txs) { + if (tx != null) { + this.internalTxs.add(tx); + } + } + } + + @Override + public void addToDeletedAddresses(Address address) { + deleteAccounts.add(address); + } + + @Override + public void addAllToDeletedAddresses(Collection
addresses) { + for (Address addr : addresses) { + if (addr != null) { + deleteAccounts.add(addr); + } + } + } + + @Override + public void addLog(IExecutionLog log) { + logs.add(log); + } + + @Override + public void addLogs(Collection logs) { + for (IExecutionLog log : logs) { + if (log != null) { + this.logs.add(log); + } + } + } + + @Override + public List getInternalTransactions() { + return internalTxs; + } + + @Override + public List
getAddressesToBeDeleted() { + return new ArrayList<>(deleteAccounts); + } + + @Override + public List getExecutionLogs() { + return logs; + } + }; + } + @Override public String toString() { return "TransactionResult { code = " + this.code diff --git a/modVM/src/org/aion/vm/BulkExecutor.java b/modVM/src/org/aion/vm/BulkExecutor.java index 34fae12e94..c999260e56 100644 --- a/modVM/src/org/aion/vm/BulkExecutor.java +++ b/modVM/src/org/aion/vm/BulkExecutor.java @@ -3,16 +3,20 @@ import static org.aion.mcf.valid.TransactionTypeRule.isValidAVMContractDeployment; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.aion.fastvm.FastVmResultCode; import org.aion.fastvm.SideEffects; import org.aion.interfaces.db.Repository; import org.aion.interfaces.db.RepositoryCache; +import org.aion.interfaces.tx.Transaction; import org.aion.interfaces.tx.TxExecSummary; +import org.aion.interfaces.vm.DataWord; import org.aion.kernel.AvmTransactionResult; import org.aion.mcf.core.AccountState; import org.aion.mcf.db.IBlockStoreBase; import org.aion.mcf.tx.TransactionTypes; +import org.aion.mcf.vm.types.DataWordImpl; import org.aion.mcf.vm.types.KernelInterfaceForFastVM; import org.aion.mcf.vm.types.Log; import org.aion.precompiled.ContractFactory; @@ -23,13 +27,13 @@ import org.aion.vm.api.interfaces.KernelInterface; import org.aion.vm.api.interfaces.ResultCode; import org.aion.vm.api.interfaces.SimpleFuture; -import org.aion.vm.api.interfaces.TransactionContext; import org.aion.vm.api.interfaces.TransactionResult; import org.aion.vm.api.interfaces.VirtualMachine; import org.aion.vm.exception.VMException; import org.aion.zero.types.AionTransaction; import org.aion.zero.types.AionTxExecSummary; import org.aion.zero.types.AionTxReceipt; +import org.aion.zero.types.IAionBlock; import org.slf4j.Logger; /** @@ -178,12 +182,19 @@ public List execute() throws VMException { this.executionBatch.getTransactions().get(currentIndex); KernelInterface vmKernel; + IAionBlock block = executionBatch.getBlock(); + if (transactionIsForAionVirtualMachine(firstTransactionInNextBatch)) { vmKernel = new KernelInterfaceForAVM( this.repositoryChild.startTracking(), this.allowNonceIncrement, - this.isLocalCall); + this.isLocalCall, + getDifficultyAsDataWord(block), + block.getNumber(), + block.getTimestamp(), + block.getNrgLimit(), + block.getCoinbase()); virtualMachineForNextBatch = VirtualMachineProvider.getVirtualMachineInstance(VM.AVM, vmKernel); nextBatchToExecute = @@ -194,7 +205,13 @@ public List execute() throws VMException { this.repositoryChild.startTracking(), this.allowNonceIncrement, this.isLocalCall, - fork040enable); + fork040enable, + getDifficultyAsDataWord(block), + block.getNumber(), + block.getTimestamp(), + block.getNrgLimit(), + block.getCoinbase()); + virtualMachineForNextBatch = VirtualMachineProvider.getVirtualMachineInstance(VM.FVM, vmKernel); nextBatchToExecute = @@ -218,12 +235,12 @@ private List executeTransactions( List summaries = new ArrayList<>(); // Run the transactions. + Transaction[] txArray = new Transaction[details.size()]; SimpleFuture[] resultsAsFutures = - virtualMachine.run(kernel, details.getExecutionContexts()); + virtualMachine.run(kernel, details.getTransactions().toArray(txArray)); // Process the results of the transactions. List transactions = details.getTransactions(); - TransactionContext[] contexts = details.getExecutionContexts(); int length = resultsAsFutures.length; for (int i = 0; i < length; i++) { @@ -236,7 +253,6 @@ private List executeTransactions( KernelInterface kernelFromVM = result.getKernelInterface(); AionTransaction transaction = transactions.get(i); - TransactionContext context = contexts[i]; // 1. Check the block energy limit & reject if necessary. long energyUsed = computeEnergyUsed(transaction.getEnergyLimit(), result); @@ -252,9 +268,9 @@ private List executeTransactions( } // 2. build the transaction summary and update the repository (the one backing - // this.kernel) with the contents of kernelFromVM accordingly. + // this kernel) with the contents of kernelFromVM accordingly. AionTxExecSummary summary = - buildSummaryAndUpdateRepository(transaction, context, kernelFromVM, result); + buildSummaryAndUpdateRepository(transaction, kernelFromVM, result); // 3. Do any post execution work and update the remaining block energy. this.blockRemainingEnergy -= @@ -272,10 +288,7 @@ private List executeTransactions( } private AionTxExecSummary buildSummaryAndUpdateRepository( - AionTransaction transaction, - TransactionContext context, - KernelInterface kernelFromVM, - TransactionResult result) { + AionTransaction transaction, KernelInterface kernelFromVM, TransactionResult result) { // TODO: should Avm assure us that this is always non-null like the fvm does? But in Avm // TODO: a null return value is actually meaningful. Need to figure this out. @@ -285,9 +298,9 @@ private AionTxExecSummary buildSummaryAndUpdateRepository( SideEffects sideEffects = new SideEffects(); if (result.getResultCode().isSuccess()) { - sideEffects.merge(context.getSideEffects()); + sideEffects.merge(result.getSideEffects()); } else { - sideEffects.addInternalTransactions(context.getSideEffects().getInternalTransactions()); + sideEffects.addInternalTransactions(result.getSideEffects().getInternalTransactions()); } // We have to do this for now, because the kernel uses the log serialization, which is not @@ -307,18 +320,32 @@ private AionTxExecSummary buildSummaryAndUpdateRepository( .result(result.getReturnData()); ResultCode resultCode = result.getResultCode(); + IAionBlock block = executionBatch.getBlock(); if (transactionIsForAionVirtualMachine(transaction)) { kernelFromVM.commitTo( new KernelInterfaceForAVM( - this.repositoryChild, this.allowNonceIncrement, this.isLocalCall)); + this.repositoryChild, + this.allowNonceIncrement, + this.isLocalCall, + getDifficultyAsDataWord(block), + block.getNumber(), + block.getTimestamp(), + block.getNrgLimit(), + block.getCoinbase())); + } else { kernelFromVM.commitTo( new KernelInterfaceForFastVM( this.repositoryChild, this.allowNonceIncrement, this.isLocalCall, - this.fork040enable)); + this.fork040enable, + getDifficultyAsDataWord(block), + block.getNumber(), + block.getTimestamp(), + block.getNrgLimit(), + block.getCoinbase())); } if (resultCode.isRejected()) { @@ -483,4 +510,13 @@ private byte getVmType(Address destination) { } } } + + private DataWord getDifficultyAsDataWord(IAionBlock block) { + // TODO: temp solution for difficulty length + byte[] diff = block.getDifficulty(); + if (diff.length > 16) { + diff = Arrays.copyOfRange(diff, diff.length - 16, diff.length); + } + return new DataWordImpl(diff); + } } diff --git a/modVM/src/org/aion/vm/KernelInterfaceForAVM.java b/modVM/src/org/aion/vm/KernelInterfaceForAVM.java index 9939076b09..d9da466771 100644 --- a/modVM/src/org/aion/vm/KernelInterfaceForAVM.java +++ b/modVM/src/org/aion/vm/KernelInterfaceForAVM.java @@ -4,11 +4,14 @@ import java.math.BigInteger; import org.aion.interfaces.db.RepositoryCache; +import org.aion.interfaces.vm.DataWord; import org.aion.mcf.core.AccountState; import org.aion.mcf.db.IBlockStoreBase; import org.aion.mcf.tx.TransactionTypes; import org.aion.mcf.valid.TransactionTypeRule; import org.aion.mcf.valid.TxNrgRule; +import org.aion.mcf.vm.types.DataWordImpl; +import org.aion.mcf.vm.types.DoubleDataWord; import org.aion.precompiled.ContractFactory; import org.aion.types.Address; import org.aion.types.ByteArrayWrapper; @@ -18,10 +21,21 @@ public class KernelInterfaceForAVM implements KernelInterface { private RepositoryCache> repositoryCache; private boolean allowNonceIncrement, isLocalCall; + private DataWord blockDifficulty; + private long blockNumber; + private long blockTimestamp; + private long blockNrgLimit; + private Address blockCoinbase; + public KernelInterfaceForAVM( RepositoryCache> repositoryCache, boolean allowNonceIncrement, - boolean isLocalCall) { + boolean isLocalCall, + DataWord blockDifficulty, + long blockNumber, + long blockTimestamp, + long blockNrgLimit, + Address blockCoinbase) { if (repositoryCache == null) { throw new NullPointerException("Cannot set null repositoryCache!"); @@ -29,12 +43,24 @@ public KernelInterfaceForAVM( this.repositoryCache = repositoryCache; this.allowNonceIncrement = allowNonceIncrement; this.isLocalCall = isLocalCall; + this.blockDifficulty = blockDifficulty; + this.blockNumber = blockNumber; + this.blockTimestamp = blockTimestamp; + this.blockNrgLimit = blockNrgLimit; + this.blockCoinbase = blockCoinbase; } @Override public KernelInterfaceForAVM makeChildKernelInterface() { return new KernelInterfaceForAVM( - this.repositoryCache.startTracking(), this.allowNonceIncrement, this.isLocalCall); + this.repositoryCache.startTracking(), + this.allowNonceIncrement, + this.isLocalCall, + this.blockDifficulty, + this.blockNumber, + this.blockTimestamp, + this.blockNrgLimit, + this.blockCoinbase); } @Override @@ -230,4 +256,33 @@ private byte getVmType(Address destination) { return storedVmType; } } + + @Override + public long getBlockNumber() { + return blockNumber; + } + + @Override + public long getBlockTimestamp() { + return blockTimestamp; + } + + @Override + public long getBlockEnergyLimit() { + return blockNrgLimit; + } + + @Override + public long getBlockDifficulty() { + if (blockDifficulty instanceof DataWordImpl) { + return ((DataWordImpl) blockDifficulty).longValue(); + } else { + return ((DoubleDataWord) blockDifficulty).longValue(); + } + } + + @Override + public Address getMinerAddress() { + return blockCoinbase; + } }