Skip to content

Commit

Permalink
feature: fully removed the use of AVM specific contract prefix
Browse files Browse the repository at this point in the history
 - corrected address generation inside AionCapabilities.java
 - expanded repository interface with check for VM deploy code
 - updated the VM spects with two supported VM codes for contract deploy
 - removed prefix checks from tests
 - expanded tests to ensure the receipt output matches the contract address
  • Loading branch information
AlexandraRoatis committed Mar 18, 2019
1 parent 974be9b commit ef3e446
Show file tree
Hide file tree
Showing 17 changed files with 132 additions and 92 deletions.
2 changes: 1 addition & 1 deletion modAion/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ext.moduleName = 'aion.zero'
test.dependsOn copyNativeLibsForModuleTests

dependencies {
compile 'network.aion:vm-api4j:0.4.0'
compile project(':aion_vm_api')
compile 'network.aion:util4j:0.4.0'
compile 'network.aion:rlp4j:0.4.0'
compile 'network.aion:crypto4j:0.4.0'
Expand Down
6 changes: 5 additions & 1 deletion modAion/src/org/aion/zero/db/AionRepositoryCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import org.aion.interfaces.db.ContractDetails;
import org.aion.interfaces.db.Repository;
import org.aion.interfaces.db.RepositoryCache;
import org.aion.types.Address;
import org.aion.mcf.core.AccountState;
import org.aion.mcf.db.AbstractRepositoryCache;
import org.aion.mcf.db.ContractDetailsCacheImpl;
import org.aion.mcf.db.IBlockStoreBase;
import org.aion.types.Address;

public class AionRepositoryCache extends AbstractRepositoryCache<IBlockStoreBase<?, ?>> {

Expand Down Expand Up @@ -251,4 +251,8 @@ public List<byte[]> getCacheTx() {
throw new UnsupportedOperationException(
"getCachelTx should be called on the tracked repository.");
}

public byte getVMUsed(Address contract) {
return repository.getVMUsed(contract);
}
}
2 changes: 1 addition & 1 deletion modAionImpl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sourceSets {
}

dependencies {
compile 'network.aion:vm-api4j:0.4.0'
compile project(':aion_vm_api')
compile 'network.aion:util4j:0.4.0'
compile 'network.aion:log4j:0.4.0'
compile 'network.aion:rlp4j:0.4.0'
Expand Down
2 changes: 1 addition & 1 deletion modAionImpl/src/org/aion/zero/impl/AionBlockchainImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ public AionBlockSummary add(AionBlock block, boolean rebuild) {
block.getNumber(),
TransactionTypeRule.isValidAVMTransactionType(tx.getTargetVM())
? VirtualMachineSpecs.AVM_CREATE_CODE
: VirtualMachineSpecs.FVM_DEFAULT_TX_TYPE,
: VirtualMachineSpecs.FVM_CREATE_CODE,
true);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ public Repository getSnapshotTo(byte[] root) {
try {
AionRepositoryImpl repo = new AionRepositoryImpl();
repo.blockStore = blockStore;
repo.contractInfoSource = contractInfoSource;
repo.cfg = cfg;
repo.stateDatabase = this.stateDatabase;
repo.stateWithArchive = this.stateWithArchive;
Expand Down Expand Up @@ -929,7 +930,7 @@ public byte getVMUsed(Address contract) {
ContractInformation ci = getIndexedContractInformation(contract);
if (ci == null) {
// defaults to FastVM for backwards compatibility
return VirtualMachineSpecs.FVM_DEFAULT_TX_TYPE;
return VirtualMachineSpecs.FVM_CREATE_CODE;
} else {
return ci.getVmUsed();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public void testDeployCryptoKitties() {
.getIndexedContractInformation(contractDeploymentTx.getContractAddress());
assertThat(ci).isNotNull();
assertThat(ci.getInceptionBlock()).isEqualTo(block.getNumber());
assertThat(ci.getVmUsed()).isEqualTo(VirtualMachineSpecs.FVM_DEFAULT_TX_TYPE);
assertThat(ci.getVmUsed()).isEqualTo(VirtualMachineSpecs.FVM_CREATE_CODE);
assertThat(ci.isComplete()).isEqualTo(true);
}

Expand Down
126 changes: 79 additions & 47 deletions modAionImpl/test/org/aion/zero/impl/vm/AvmHelloWorldTest.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
package org.aion.zero.impl.vm;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static com.google.common.truth.Truth.assertThat;

import java.math.BigInteger;
import java.util.Collections;
import org.aion.avm.api.ABIEncoder;
import org.aion.avm.core.NodeEnvironment;
import org.aion.avm.core.dappreading.JarBuilder;
import org.aion.avm.core.util.CodeAndArguments;
import org.aion.interfaces.vm.VirtualMachineSpecs;
import org.aion.types.Address;
import org.aion.crypto.AddressSpecs;
import org.aion.crypto.ECKey;
import org.aion.interfaces.vm.VirtualMachineSpecs;
import org.aion.mcf.core.ImportResult;
import org.aion.types.Address;
import org.aion.vm.VirtualMachineProvider;

import org.aion.zero.impl.StandaloneBlockchain;
import org.aion.zero.impl.vm.contracts.AvmHelloWorld;
import org.aion.zero.impl.types.AionBlock;
import org.aion.zero.impl.types.AionBlockSummary;
import org.aion.zero.impl.vm.contracts.AvmHelloWorld;
import org.aion.zero.types.AionTransaction;
import org.aion.zero.types.AionTxReceipt;
import org.apache.commons.lang3.tuple.Pair;
Expand All @@ -44,11 +42,12 @@ public static void tearDownAvm() {

@Before
public void setup() {
StandaloneBlockchain.Bundle bundle = new StandaloneBlockchain.Builder()
.withDefaultAccounts()
.withValidatorConfiguration("simple")
.withAvmEnabled()
.build();
StandaloneBlockchain.Bundle bundle =
new StandaloneBlockchain.Builder()
.withDefaultAccounts()
.withValidatorConfiguration("simple")
.withAvmEnabled()
.build();
this.blockchain = bundle.bc;
this.deployerKey = bundle.privateKeys.get(0);
}
Expand All @@ -62,74 +61,107 @@ public void tearDown() {
@Test
public void testDeployContract() {
byte[] jar = getJarBytes();
AionTransaction transaction = newTransaction(
BigInteger.ZERO,
Address.wrap(deployerKey.getAddress()),
null,
jar,
5_000_000);
AionTransaction transaction =
newTransaction(
BigInteger.ZERO,
Address.wrap(deployerKey.getAddress()),
null,
jar,
5_000_000);
transaction.sign(this.deployerKey);

AionBlock block = this.blockchain.createNewBlock(this.blockchain.getBestBlock(), Collections.singletonList(transaction), false);
Pair<ImportResult, AionBlockSummary> connectResult = this.blockchain.tryToConnectAndFetchSummary(block);
AionBlock block =
this.blockchain.createNewBlock(
this.blockchain.getBestBlock(),
Collections.singletonList(transaction),
false);
Pair<ImportResult, AionBlockSummary> connectResult =
this.blockchain.tryToConnectAndFetchSummary(block);
AionTxReceipt receipt = connectResult.getRight().getReceipts().get(0);

// Check the block was imported, the contract has the Avm prefix, and deployment succeeded.
assertEquals(ImportResult.IMPORTED_BEST, connectResult.getLeft());
assertEquals(NodeEnvironment.CONTRACT_PREFIX, receipt.getTransactionOutput()[0]);
assertTrue(receipt.isSuccessful());
assertThat(connectResult.getLeft()).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(receipt.getTransactionOutput()[0]).isEqualTo(AddressSpecs.A0_IDENTIFIER);
assertThat(receipt.isSuccessful()).isTrue();

// verify that the output is indeed the contract address
assertThat(transaction.getContractAddress().toBytes())
.isEqualTo(receipt.getTransactionOutput());
}

@Test
public void testDeployAndCallContract() {
// Deploy the contract.
byte[] jar = getJarBytes();
AionTransaction transaction = newTransaction(
BigInteger.ZERO,
Address.wrap(deployerKey.getAddress()),
null,
jar,
5_000_000);
AionTransaction transaction =
newTransaction(
BigInteger.ZERO,
Address.wrap(deployerKey.getAddress()),
null,
jar,
5_000_000);
transaction.sign(this.deployerKey);

AionBlock block = this.blockchain.createNewBlock(this.blockchain.getBestBlock(), Collections.singletonList(transaction), false);
Pair<ImportResult, AionBlockSummary> connectResult = this.blockchain.tryToConnectAndFetchSummary(block);
AionBlock block =
this.blockchain.createNewBlock(
this.blockchain.getBestBlock(),
Collections.singletonList(transaction),
false);
Pair<ImportResult, AionBlockSummary> connectResult =
this.blockchain.tryToConnectAndFetchSummary(block);
AionTxReceipt receipt = connectResult.getRight().getReceipts().get(0);

// Check the block was imported, the contract has the Avm prefix, and deployment succeeded.
assertEquals(ImportResult.IMPORTED_BEST, connectResult.getLeft());
assertEquals(NodeEnvironment.CONTRACT_PREFIX, receipt.getTransactionOutput()[0]);
assertTrue(receipt.isSuccessful());
assertThat(connectResult.getLeft()).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(receipt.getTransactionOutput()[0]).isEqualTo(AddressSpecs.A0_IDENTIFIER);
assertThat(receipt.isSuccessful()).isTrue();

Address contract = Address.wrap(receipt.getTransactionOutput());
// verify that the output is indeed the contract address
assertThat(transaction.getContractAddress()).isEqualTo(contract);
byte[] call = getCallArguments();
transaction = newTransaction(
BigInteger.ONE,
Address.wrap(deployerKey.getAddress()),
contract,
call,
2_000_000);
transaction =
newTransaction(
BigInteger.ONE,
Address.wrap(deployerKey.getAddress()),
contract,
call,
2_000_000);
transaction.sign(this.deployerKey);

block = this.blockchain.createNewBlock(this.blockchain.getBestBlock(), Collections.singletonList(transaction), false);
block =
this.blockchain.createNewBlock(
this.blockchain.getBestBlock(),
Collections.singletonList(transaction),
false);
connectResult = this.blockchain.tryToConnectAndFetchSummary(block);
receipt = connectResult.getRight().getReceipts().get(0);

// Check the block was imported and the transaction was successful.
assertEquals(ImportResult.IMPORTED_BEST, connectResult.getLeft());
assertTrue(receipt.isSuccessful());
assertThat(connectResult.getLeft()).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(receipt.isSuccessful()).isTrue();
}

private byte[] getCallArguments() {
return ABIEncoder.encodeMethodArguments("sayHello");
}

private byte[] getJarBytes() {
return new CodeAndArguments(JarBuilder.buildJarForMainAndClasses(AvmHelloWorld.class), new byte[0]).encodeToBytes();
return new CodeAndArguments(
JarBuilder.buildJarForMainAndClasses(AvmHelloWorld.class), new byte[0])
.encodeToBytes();
}

private AionTransaction newTransaction(BigInteger nonce, Address sender, Address destination, byte[] data, long energyLimit) {
return new AionTransaction(nonce.toByteArray(), sender, destination, BigInteger.ZERO.toByteArray(), data, energyLimit, 1, VirtualMachineSpecs.AVM_CREATE_CODE);
private AionTransaction newTransaction(
BigInteger nonce, Address sender, Address destination, byte[] data, long energyLimit) {
return new AionTransaction(
nonce.toByteArray(),
sender,
destination,
BigInteger.ZERO.toByteArray(),
data,
energyLimit,
1,
VirtualMachineSpecs.AVM_CREATE_CODE);
}

}
15 changes: 7 additions & 8 deletions modAionImpl/test/org/aion/zero/impl/vm/StatefulnessTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@
import java.math.BigInteger;
import java.util.Arrays;
import org.aion.avm.api.ABIEncoder;
import org.aion.avm.core.NodeEnvironment;
import org.aion.avm.core.dappreading.JarBuilder;
import org.aion.avm.core.util.CodeAndArguments;
import org.aion.interfaces.vm.VirtualMachineSpecs;
import org.aion.types.Address;
import org.aion.crypto.AddressSpecs;
import org.aion.crypto.ECKey;
import org.aion.interfaces.vm.VirtualMachineSpecs;
import org.aion.mcf.core.ImportResult;
import org.aion.types.Address;
import org.aion.vm.VirtualMachineProvider;

import org.aion.zero.impl.StandaloneBlockchain;
import org.aion.zero.impl.vm.contracts.Statefulness;
import org.aion.zero.impl.types.AionBlock;
import org.aion.zero.impl.types.AionBlockSummary;
import org.aion.zero.impl.vm.contracts.Statefulness;
import org.aion.zero.types.AionTransaction;
import org.aion.zero.types.AionTxReceipt;
import org.apache.commons.lang3.RandomUtils;
Expand Down Expand Up @@ -73,7 +72,7 @@ public void testDeployContract() {
AionTxReceipt receipt = deployContract();

// Check the contract has the Avm prefix, and deployment succeeded.
assertEquals(NodeEnvironment.CONTRACT_PREFIX, receipt.getTransactionOutput()[0]);
assertEquals(AddressSpecs.A0_IDENTIFIER, receipt.getTransactionOutput()[0]);
assertTrue(receipt.isSuccessful());
}

Expand All @@ -85,7 +84,7 @@ public void testStateOfActorsAfterDeployment() {
AionTxReceipt receipt = deployContract();

// Check the contract has the Avm prefix, and deployment succeeded, and grab the address.
assertEquals(NodeEnvironment.CONTRACT_PREFIX, receipt.getTransactionOutput()[0]);
assertEquals(AddressSpecs.A0_IDENTIFIER, receipt.getTransactionOutput()[0]);
assertTrue(receipt.isSuccessful());
Address contract = Address.wrap(receipt.getTransactionOutput());

Expand All @@ -111,7 +110,7 @@ public void testUsingCallInContract() {
AionTxReceipt receipt = deployContract();

// Check the contract has the Avm prefix, and deployment succeeded, and grab the address.
assertEquals(NodeEnvironment.CONTRACT_PREFIX, receipt.getTransactionOutput()[0]);
assertEquals(AddressSpecs.A0_IDENTIFIER, receipt.getTransactionOutput()[0]);
assertTrue(receipt.isSuccessful());
Address contract = Address.wrap(receipt.getTransactionOutput());

Expand Down
2 changes: 1 addition & 1 deletion modMcf/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ test.dependsOn copyNativeLibsForModuleTests
clean.dependsOn deleteNativeLibs

dependencies {
compile 'network.aion:vm-api4j:0.4.0'
compile project(':aion_vm_api')
compile 'network.aion:util4j:0.4.0'
compile 'network.aion:log4j:0.4.0'
compile 'network.aion:rlp4j:0.4.0'
Expand Down
2 changes: 1 addition & 1 deletion modMcf/src/org/aion/mcf/types/AbstractTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public AbstractTransaction(byte[] nonce, Address receiveAddress, byte[] value, b
this.value = value;
this.data = data;
// default type 0x01; reserve date for multi-type transaction
this.type = VirtualMachineSpecs.FVM_DEFAULT_TX_TYPE;
this.type = VirtualMachineSpecs.FVM_CREATE_CODE;
}

public AbstractTransaction(
Expand Down
15 changes: 13 additions & 2 deletions modMcf/src/org/aion/mcf/valid/TransactionTypeRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,22 @@
*/
public class TransactionTypeRule {

/**
* Compares the given transaction type with all the transaction types allowed by the FastVM.
*
* @param type the type of a contract creation transaction
* @return {@code true} is this is a FastVM transaction, {@code false} otherwise
*/
public static boolean isValidFVMTransactionType(byte type) {
return type == VirtualMachineSpecs.FVM_DEFAULT_TX_TYPE
|| type == VirtualMachineSpecs.FVM_ALLOWED_TX_TYPE;
return type == VirtualMachineSpecs.FVM_CREATE_CODE;
}

/**
* Compares the given transaction type with all the transaction types allowed by the AVM.
*
* @param type the type of a contract creation transaction
* @return {@code true} is this is an AVM transaction, {@code false} otherwise
*/
public static boolean isValidAVMTransactionType(byte type) {
return type == VirtualMachineSpecs.AVM_CREATE_CODE;
}
Expand Down
2 changes: 1 addition & 1 deletion modVM/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ext.moduleName = 'aion.vm'

dependencies {
compile 'network.aion:vm-api4j:0.4.0'
compile project(':aion_vm_api')
compile 'network.aion:util4j:0.4.0'
compile 'network.aion:crypto4j:0.4.0'

Expand Down
13 changes: 2 additions & 11 deletions modVM/src/org/aion/vm/AionCapabilities.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package org.aion.vm;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import org.aion.avm.core.IExternalCapabilities;
import org.aion.avm.core.NodeEnvironment;
import org.aion.crypto.HashUtil;
import org.aion.types.Address;
import org.aion.vm.api.interfaces.TransactionInterface;
Expand Down Expand Up @@ -32,12 +29,6 @@ public boolean verifyEdDSA(byte[] bytes, byte[] bytes1, byte[] bytes2) {

@Override
public Address generateContractAddress(TransactionInterface tx) {
Address sender = tx.getSenderAddress();
long nonce = new BigInteger(tx.getNonce()).longValue();
ByteBuffer buffer =
ByteBuffer.allocate(Address.SIZE + Long.BYTES).put(sender.toBytes()).putLong(nonce);
byte[] hash = sha256(buffer.array());
hash[0] = NodeEnvironment.CONTRACT_PREFIX;
return Address.wrap(hash);
return Address.wrap(HashUtil.calcNewAddr(tx.getSenderAddress().toBytes(), tx.getNonce()));
}
}
}
Loading

0 comments on commit ef3e446

Please sign in to comment.