implement the code size opcodes (#107)

This commit is contained in:
Cyrill Leutwiler
2024-10-31 11:46:47 +01:00
committed by GitHub
parent 68564f9866
commit 43d2ef3ce9
6 changed files with 484 additions and 418 deletions
Generated
+357 -357
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -67,7 +67,7 @@ log = { version = "0.4" }
# polkadot-sdk and friends
codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
scale-info = { version = "2.11.1", default-features = false }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "db40a66db71e8e7fe943dda5cd0e28078efa2a19" }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "2b6b69641ccff4d7aa9c32051bbb2f1e775ef8cc" }
# llvm
[workspace.dependencies.inkwell]
+3 -5
View File
@@ -105,9 +105,7 @@ contract ERC20Tester {
ERC20 token = new ERC20();
assert(token.decimals() == 18);
// use call directly when code_size is implemented on pallet-revive
address(token).call(abi.encodeWithSignature("mint(uint256)", 300));
token.mint(300);
assert(token.balanceOf(address(this)) == 300);
token.transfer(BOB, 100);
assert(token.balanceOf(address(this)) == 200);
@@ -119,7 +117,7 @@ contract ERC20Tester {
assert(token.balanceOf(BOB) == 200);
assert(token.balanceOf(address(this)) == 100);
address(token).call(abi.encodeWithSignature("burn(uint256)", 100));
token.burn(100);
assert(token.balanceOf(address(this)) == 0);
}
}
}
+108 -24
View File
@@ -321,6 +321,114 @@ fn ext_code_hash() {
.run();
}
#[test]
fn ext_code_size() {
let alice = Address::from(ALICE.0);
let own_address = alice.create(0);
let baseline_address = alice.create2([0u8; 32], keccak256(Contract::baseline().pvm_runtime));
let own_code_size = U256::from(
Contract::ext_code_size(Default::default())
.pvm_runtime
.len(),
);
let baseline_code_size = U256::from(Contract::baseline().pvm_runtime.len());
Specs {
actions: vec![
// Instantiate the test contract
instantiate("contracts/ExtCode.sol", "ExtCode").remove(0),
// Instantiate the baseline contract
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Solidity {
path: Some("contracts/Baseline.sol".into()),
contract: "Baseline".to_string(),
solc_optimizer: None,
pipeline: None,
},
data: vec![],
salt: OptionalHex::from([0; 32]),
},
// Alice is not a contract and returns a code size of 0
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(alice).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from([0u8; 32].to_vec()),
gas_consumed: None,
}),
// Unknown address returns a code size of 0
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(Address::from([0xff; 20])).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from([0u8; 32].to_vec()),
gas_consumed: None,
}),
// Own address via extcodesize returns own code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(own_address).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(own_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
// Own address via codesize returns own code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::code_size().calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(own_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
// Baseline address returns the baseline code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(baseline_address).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(baseline_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
],
..Default::default()
}
.run();
}
/*
// These test were implement for the mock-runtime and need to be ported yet.
@@ -349,28 +457,4 @@ fn create2_failure() {
assert_eq!(output.flags, ReturnFlags::Revert);
}
#[test]
fn ext_code_size() {
let contract = Contract::ext_code_size(Transaction::default_address());
let (_, output) = assert_success(&contract, false);
let received = U256::from_be_slice(&output.data);
let expected = U256::from(contract.pvm_runtime.len());
assert_eq!(received, expected);
let contract = Contract::ext_code_size(Default::default());
let (_, output) = assert_success(&contract, false);
let received = U256::from_be_slice(&output.data);
let expected = U256::ZERO;
assert_eq!(received, expected);
}
#[test]
fn code_size() {
let contract = Contract::code_size();
let (_, output) = assert_success(&contract, false);
let expected = U256::from(contract.pvm_runtime.len());
let received = U256::from_be_slice(&output.data);
assert_eq!(expected, received);
}
*/
+14 -30
View File
@@ -1,7 +1,5 @@
//! Translates the external code operations.
use inkwell::values::BasicValue;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
@@ -14,37 +12,23 @@ pub fn size<'ctx, D>(
where
D: Dependency + Clone,
{
let address_pointer = match address {
Some(address) => {
let address_pointer = context.build_alloca(context.word_type(), "value");
context.build_store(address_pointer, address)?;
address_pointer
}
None => context.sentinel_pointer(),
let address = match address {
Some(address) => address,
None => super::context::address(context)?.into_int_value(),
};
let address_pointer_casted = context.builder().build_ptr_to_int(
address_pointer.value,
context.xlen_type(),
"address_pointer",
)?;
let value = context
.build_runtime_call(
revive_runtime_api::polkavm_imports::CODE_SIZE,
&[address_pointer_casted.into()],
)
.unwrap_or_else(|| {
panic!(
"{} should return a value",
revive_runtime_api::polkavm_imports::CODE_SIZE
)
})
.into_int_value();
let address_pointer = context.build_address_argument_store(address)?;
let output_pointer = context.build_alloca_at_entry(context.word_type(), "output_pointer");
Ok(context
.builder()
.build_int_z_extend(value, context.word_type(), "extcodesize")?
.as_basic_value_enum())
context.build_runtime_call(
revive_runtime_api::polkavm_imports::CODE_SIZE,
&[
address_pointer.to_int(context).into(),
output_pointer.to_int(context).into(),
],
);
context.build_load(output_pointer, "code_size")
}
/// Translates the `extcodehash` instruction.
+1 -1
View File
@@ -78,7 +78,7 @@ POLKAVM_IMPORT(void, caller, uint32_t)
POLKAVM_IMPORT(void, chain_id, uint32_t)
POLKAVM_IMPORT(uint32_t, code_size, uint32_t)
POLKAVM_IMPORT(uint32_t, code_size, uint32_t, uint32_t)
POLKAVM_IMPORT(void, code_hash, uint32_t, uint32_t)