Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 1.2-rc into develop #731

Merged
merged 10 commits into from
Jun 16, 2022
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com).

- Automatically create account for undeposited sender [#710](https://github.com/nervosnetwork/godwoken/pull/710)

## [v1.2.0-rc1] - 2020-06-11
## [v1.2.1-rc1] - 2022-06-15
- Refresh readonly mem-pool when receives new mem-block [#721](https://github.com/nervosnetwork/godwoken/pull/721)
- fix: reject transactions has less gas than the intrinsic gas [#725](https://github.com/nervosnetwork/godwoken/pull/725)

## [v1.2.0-rc1] - 2022-06-11

- Support packaging failed transactions into layer2 block [#684](https://github.com/nervosnetwork/godwoken/pull/684)
- Support upgrade backend executable binaries [#713](https://github.com/nervosnetwork/godwoken/pull/713)
- Support new option `max_txs`, `max_deposits` and `max_withdrawals` in config file, these options controls the maximum number of each items in a block [#714](https://github.com/nervosnetwork/godwoken/pull/714)
- Return committed info on withdrawal query RPC [#706](https://github.com/nervosnetwork/godwoken/pull/706)

## [v1.1.4] - 2020-05-30
## [v1.1.4] - 2022-05-30
- Improve the withdrawal packaging performance [#701](https://github.com/nervosnetwork/godwoken/pull/701)
- Improve the performance of deposits [#703](https://github.com/nervosnetwork/godwoken/pull/703)

Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/block-producer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "gw-block-producer"
version = "1.2.0"
version = "1.2.1"
authors = ["Nervos Network"]
edition = "2021"

Expand Down
42 changes: 7 additions & 35 deletions crates/generator/src/account_lock_manage/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use gw_types::{
bytes::Bytes,
packed::{L2Transaction, RawL2Transaction, Script},
};
use gw_utils::polyjuice_parser::PolyjuiceParser;
use lazy_static::lazy_static;
use secp256k1::recovery::{RecoverableSignature, RecoveryId};
use sha3::{Digest, Keccak256};
Expand Down Expand Up @@ -376,30 +377,14 @@ fn calc_godwoken_signing_message(
}

fn try_assemble_polyjuice_args(raw_tx: RawL2Transaction, receiver_script: Script) -> Option<Bytes> {
let args: Bytes = raw_tx.args().unpack();
if args.len() < 52 {
return None;
}
if args[0..7] != b"\xFF\xFF\xFFPOLY"[..] {
return None;
}
let parser = PolyjuiceParser::from_raw_l2_tx(&raw_tx)?;
let mut stream = rlp::RlpStream::new();
stream.begin_unbounded_list();
let nonce: u32 = raw_tx.nonce().unpack();
stream.append(&nonce);
let gas_price = {
let mut data = [0u8; 16];
data.copy_from_slice(&args[16..32]);
u128::from_le_bytes(data)
};
stream.append(&gas_price);
let gas_limit = {
let mut data = [0u8; 8];
data.copy_from_slice(&args[8..16]);
u64::from_le_bytes(data)
};
stream.append(&gas_limit);
let to = if args[7] == 3 {
stream.append(&parser.gas_price());
stream.append(&parser.gas());
let to = if parser.is_create() {
// 3 for EVMC_CREATE
vec![0u8; 0]
} else {
Expand All @@ -418,21 +403,8 @@ fn try_assemble_polyjuice_args(raw_tx: RawL2Transaction, receiver_script: Script
to
};
stream.append(&to);
let value = {
let mut data = [0u8; 16];
data.copy_from_slice(&args[32..48]);
u128::from_le_bytes(data)
};
stream.append(&value);
let payload_length = {
let mut data = [0u8; 4];
data.copy_from_slice(&args[48..52]);
u32::from_le_bytes(data)
} as usize;
if args.len() != 52 + payload_length {
return None;
}
stream.append(&args[52..52 + payload_length].to_vec());
stream.append(&parser.value());
stream.append(&parser.data().to_vec());
stream.append(&raw_tx.chain_id().unpack());
stream.append(&0u8);
stream.append(&0u8);
Expand Down
2 changes: 2 additions & 0 deletions crates/generator/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ pub enum TransactionError {
NoCost,
#[error("Nonce Overflow")]
NonceOverflow,
#[error("Intrinsic gas")]
IntrinsicGas,
}

impl From<VMError> for TransactionError {
Expand Down
6 changes: 3 additions & 3 deletions crates/generator/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -689,17 +689,17 @@ impl Generator {
{
run_result.write.logs.push(log);
}
let args = tx.extract_tx_args().ok_or(TransactionError::NoCost)?;
let parser = tx.parser().ok_or(TransactionError::NoCost)?;
let gas_used = match read_polyjuice_gas_used(&run_result) {
Some(gas_used) => gas_used,
None => {
log::warn!(
"[gw-generator] failed to parse gas_used, use gas_limit instead"
);
args.gas_limit
parser.gas()
}
};
gw_types::U256::from(gas_used).checked_mul(args.gas_price.into())
gw_types::U256::from(gas_used).checked_mul(parser.gas_price().into())
}
}
.ok_or(TransactionError::NoCost)?;
Expand Down
92 changes: 43 additions & 49 deletions crates/generator/src/typed_transaction/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use gw_types::{
prelude::*,
U256,
};
use gw_utils::polyjuice_parser::PolyjuiceParser;

/// Types Transaction
pub enum TypedRawTransaction {
Expand Down Expand Up @@ -123,64 +124,57 @@ impl SimpleUDTTx {
}
}

pub struct PolyjuiceTxArgs {
pub value: u128,
pub gas_price: u128,
pub gas_limit: u64,
}

pub struct PolyjuiceTx(RawL2Transaction);
impl PolyjuiceTx {
pub fn extract_tx_args(&self) -> Option<PolyjuiceTxArgs> {
let args: Bytes = self.0.args().unpack();
if args.len() < 52 {
log::error!(
"[gw-generator] parse PolyjuiceTx error, wrong args.len expected: >= 52, actual: {}",
args.len()
);
return None;
}
if args[0..7] != b"\xFF\xFF\xFFPOLY"[..] {
log::error!("[gw-generator] parse PolyjuiceTx error, invalid args",);
return None;
}

// parse gas price, gas limit, value
let gas_price = {
let mut data = [0u8; 16];
data.copy_from_slice(&args[16..32]);
u128::from_le_bytes(data)
};
let gas_limit = {
let mut data = [0u8; 8];
data.copy_from_slice(&args[8..16]);
u64::from_le_bytes(data)
};

let value = {
let mut data = [0u8; 16];
data.copy_from_slice(&args[32..48]);
u128::from_le_bytes(data)
};
Some(PolyjuiceTxArgs {
value,
gas_price,
gas_limit,
})
pub fn parser(&self) -> Option<PolyjuiceParser> {
PolyjuiceParser::from_raw_l2_tx(&self.0)
}

/// Total cost of a tx, sender's balance must sufficient to pay Cost(value + gas_price * gas_limit)
pub fn cost(&self) -> Option<U256> {
match self.extract_tx_args() {
Some(PolyjuiceTxArgs {
value,
gas_price,
gas_limit,
}) => {
let cost = value.checked_add(gas_price.checked_mul(gas_limit.into())?)?;
match self.parser() {
Some(parser) => {
let cost = parser
.value()
.checked_add(parser.gas_price().checked_mul(parser.gas().into())?)?;
cost.try_into().ok()
}
None => None,
}
}

/// Intrinsic gas
pub fn intrinsic_gas(&self) -> Option<u64> {
// Minimal gas of a normal transaction
const MIN_TX_GAS: u64 = 21000;
// Minimal gas of a transaction that creates a contract
const MIN_CONTRACT_CREATION_TX_GAS: u64 = 53000;
// Gas per byte of non zero data attached to a transaction
const DATA_NONE_ZERO_GAS: u64 = 16;
// Gas per byte of data attached to a transaction
const DATA_ZERO_GAS: u64 = 4;

let p = self.parser()?;

// Set the starting gas for the raw transaction
let mut gas = if p.is_create() {
MIN_CONTRACT_CREATION_TX_GAS
} else {
MIN_TX_GAS
};
if p.data_size() > 0 {
let mut non_zeros = 0u64;
for &b in p.data() {
if b != 0 {
non_zeros += 1;
}
}
// nonzero bytes gas
gas = gas.checked_add(non_zeros.checked_mul(DATA_NONE_ZERO_GAS)?)?;
let zeros = p.data_size() as u64 - non_zeros;
// zero bytes gas
gas = gas.checked_add(zeros.checked_mul(DATA_ZERO_GAS)?)?;
}
Some(gas)
}
}
28 changes: 17 additions & 11 deletions crates/generator/src/verification/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,29 @@ impl<'a, S: State + CodeStore> TransactionVerifier<'a, S> {
.state
.get_registry_address_by_script_hash(ETH_REGISTRY_ACCOUNT_ID, &sender_script_hash)?
.ok_or(AccountError::RegistryAddressNotFound)?;
// get balance
let balance = self
.state
.get_sudt_balance(CKB_SUDT_ACCOUNT_ID, &sender_address)?;
// get balance
let tx_cost = {
let tx_type = get_tx_type(self.rollup_context, self.state, &tx.raw())?;
let typed_tx = TypedRawTransaction::from_tx(tx.raw(), tx_type)
.ok_or(AccountError::UnknownScript)?;
// reject txs has no cost, these transaction can only be execute without modify state tree
typed_tx
.cost()
.map(Into::into)
.ok_or(TransactionError::NoCost)?
};
let tx_type = get_tx_type(self.rollup_context, self.state, &tx.raw())?;
let typed_tx =
TypedRawTransaction::from_tx(tx.raw(), tx_type).ok_or(AccountError::UnknownScript)?;
// reject txs has no cost, these transaction can only be execute without modify state tree
let tx_cost = typed_tx
.cost()
.map(Into::into)
.ok_or(TransactionError::NoCost)?;
if balance < tx_cost {
return Err(TransactionError::InsufficientBalance.into());
}
// Intrinsic Gas
if let TypedRawTransaction::Polyjuice(tx) = typed_tx {
let p = tx.parser().ok_or(TransactionError::IntrinsicGas)?;
let intrinsic_gas = tx.intrinsic_gas().ok_or(TransactionError::IntrinsicGas)?;
if p.gas() < intrinsic_gas {
return Err(TransactionError::IntrinsicGas.into());
}
}

Ok(())
}
Expand Down
Loading