diff --git a/README.md b/README.md
index f388da201a..87799e9272 100644
--- a/README.md
+++ b/README.md
@@ -198,7 +198,7 @@ After following these steps, Juno should be up and running on your machine, util
## 🛣 Roadmap
-### Phase 1
+### Phase 1: Permissionless access to Starknet ✅
@@ -232,7 +232,7 @@ After following these steps, Juno should be up and running on your machine, util
-### Phase 2
+### Phase 2: Full JSON RPC Support ✅
@@ -262,6 +262,35 @@ The focus of Phase 2 will be to Verify the state from layer 1 and implement the
+### Phase 3: Starknet decentralization begins 🚧
+
+
+
+
+Juno can synchronize Starknet state from other full nodes with the aim of decentralizing Starknet by removing the dependency from the centralized sequencer.
+
+
+Snap sync is implemented, significantly reducing sync times.
+
+
+
+### Phase 4: Juno becomes a Starknet Sequencer 🔜
+
+
+
+
+The decentralization of Starknet is complete! Juno becomes a sequencer and participates in L2 consensus to secure the network. Juno has multiple modes of operation:
+
+
+• Light client: provides fast permissionless access to Starknet with minimal verification.
+
+• Full Node: complete verification of Starknet state along with transaction execution.
+
+• Sequencer: secure the network by taking part in the L2 consensus mechanism.
+
+
+
+
## 👍 Contribute
We welcome PRs from external contributors and would love to help you get up to speed.
diff --git a/mocks/mock_vm.go b/mocks/mock_vm.go
index 4622e705d7..a1c9255b3b 100644
--- a/mocks/mock_vm.go
+++ b/mocks/mock_vm.go
@@ -57,9 +57,9 @@ func (mr *MockVMMockRecorder) Call(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg
}
// Execute mocks base method.
-func (m *MockVM) Execute(arg0 []core.Transaction, arg1 []core.Class, arg2, arg3 uint64, arg4 *felt.Felt, arg5 core.StateReader, arg6 utils.Network, arg7 []*felt.Felt, arg8, arg9 bool, arg10 *felt.Felt, arg11 bool) ([]*felt.Felt, []json.RawMessage, error) {
+func (m *MockVM) Execute(arg0 []core.Transaction, arg1 []core.Class, arg2, arg3 uint64, arg4 *felt.Felt, arg5 core.StateReader, arg6 utils.Network, arg7 []*felt.Felt, arg8, arg9 bool, arg10, arg11 *felt.Felt, arg12 bool) ([]*felt.Felt, []json.RawMessage, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Execute", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)
+ ret := m.ctrl.Call(m, "Execute", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
ret0, _ := ret[0].([]*felt.Felt)
ret1, _ := ret[1].([]json.RawMessage)
ret2, _ := ret[2].(error)
@@ -67,7 +67,7 @@ func (m *MockVM) Execute(arg0 []core.Transaction, arg1 []core.Class, arg2, arg3
}
// Execute indicates an expected call of Execute.
-func (mr *MockVMMockRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 any) *gomock.Call {
+func (mr *MockVMMockRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockVM)(nil).Execute), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockVM)(nil).Execute), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
}
diff --git a/node/throttled_vm.go b/node/throttled_vm.go
index c1857f5776..08e26f8c54 100644
--- a/node/throttled_vm.go
+++ b/node/throttled_vm.go
@@ -31,7 +31,7 @@ func (tvm *ThrottledVM) Call(contractAddr, classHash, selector *felt.Felt, calld
func (tvm *ThrottledVM) Execute(txns []core.Transaction, declaredClasses []core.Class, blockNumber, blockTimestamp uint64,
sequencerAddress *felt.Felt, state core.StateReader, network utils.Network, paidFeesOnL1 []*felt.Felt,
- skipChargeFee, skipValidate bool, gasPrice *felt.Felt, legacyTraceJSON bool,
+ skipChargeFee, skipValidate bool, gasPriceWEI *felt.Felt, gasPriceSTRK *felt.Felt, legacyTraceJSON bool,
) ([]*felt.Felt, []json.RawMessage, error) {
var ret []*felt.Felt
var traces []json.RawMessage
@@ -39,7 +39,7 @@ func (tvm *ThrottledVM) Execute(txns []core.Transaction, declaredClasses []core.
return ret, traces, throttler.Do(func(vm *vm.VM) error {
var err error
ret, traces, err = (*vm).Execute(txns, declaredClasses, blockNumber, blockTimestamp, sequencerAddress,
- state, network, paidFeesOnL1, skipChargeFee, skipValidate, gasPrice, legacyTraceJSON)
+ state, network, paidFeesOnL1, skipChargeFee, skipValidate, gasPriceWEI, gasPriceSTRK, legacyTraceJSON)
return err
})
}
diff --git a/rpc/handlers.go b/rpc/handlers.go
index 293cde60fe..d8da53c3d4 100644
--- a/rpc/handlers.go
+++ b/rpc/handlers.go
@@ -1349,7 +1349,7 @@ func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTra
sequencerAddress = core.NetworkBlockHashMetaInfo(h.network).FallBackSequencerAddress
}
overallFees, traces, err := h.vm.Execute(txns, classes, blockNumber, header.Timestamp, sequencerAddress,
- state, h.network, paidFeesOnL1, skipFeeCharge, skipValidate, header.GasPrice, legacyTraceJSON)
+ state, h.network, paidFeesOnL1, skipFeeCharge, skipValidate, header.GasPrice, header.GasPriceSTRK, legacyTraceJSON)
if err != nil {
if errors.Is(err, utils.ErrResourceBusy) {
return nil, ErrUnexpectedError.CloneWithData(err.Error())
@@ -1482,7 +1482,7 @@ func (h *Handler) traceBlockTransactions(ctx context.Context, block *core.Block,
}
_, traces, err := h.vm.Execute(block.Transactions, classes, blockNumber, block.Header.Timestamp,
- sequencerAddress, state, h.network, paidFeesOnL1, false, false, block.Header.GasPrice, legacyJSON)
+ sequencerAddress, state, h.network, paidFeesOnL1, false, false, block.Header.GasPrice, block.Header.GasPriceSTRK, legacyJSON)
if err != nil {
if errors.Is(err, utils.ErrResourceBusy) {
return nil, ErrUnexpectedError.CloneWithData(err.Error())
diff --git a/rpc/handlers_test.go b/rpc/handlers_test.go
index 27c8ee34f8..305194304c 100644
--- a/rpc/handlers_test.go
+++ b/rpc/handlers_test.go
@@ -2055,10 +2055,10 @@ func TestEstimateMessageFee(t *testing.T) {
expectedGasConsumed := new(felt.Felt).SetUint64(37)
mockVM.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(),
- gomock.Any(), utils.Mainnet, gomock.Any(), gomock.Any(), gomock.Any(), latestHeader.GasPrice, gomock.Any()).DoAndReturn(
+ gomock.Any(), utils.Mainnet, gomock.Any(), gomock.Any(), gomock.Any(), latestHeader.GasPrice, latestHeader.GasPriceSTRK, gomock.Any()).DoAndReturn(
func(txns []core.Transaction, declaredClasses []core.Class, blockNumber, blockTimestamp uint64,
sequencerAddress *felt.Felt, state core.StateReader, network utils.Network, paidFeesOnL1 []*felt.Felt,
- skipChargeFee, skipValidate bool, gasPrice *felt.Felt, legacyTraceJson bool,
+ skipChargeFee, skipValidate bool, gasPriceWei, gasPriceSTRK *felt.Felt, legacyTraceJson bool,
) ([]*felt.Felt, []json.RawMessage, error) {
require.Len(t, txns, 1)
assert.NotNil(t, txns[0].(*core.L1HandlerTransaction))
@@ -2069,7 +2069,7 @@ func TestEstimateMessageFee(t *testing.T) {
assert.NotNil(t, sequencerAddress)
assert.Len(t, paidFeesOnL1, 1)
- actualFee := new(felt.Felt).Mul(expectedGasConsumed, gasPrice)
+ actualFee := new(felt.Felt).Mul(expectedGasConsumed, gasPriceWei)
return []*felt.Felt{actualFee}, []json.RawMessage{{}}, nil
},
)
@@ -2138,7 +2138,7 @@ func TestTraceTransaction(t *testing.T) {
"fee_transfer_invocation": {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"]}], "messages": []}], "events": [], "messages": []}
}`)
mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, header.Number, header.Timestamp, header.SequencerAddress,
- gomock.Any(), utils.Mainnet, []*felt.Felt{}, false, false, gomock.Any(), false).Return(nil, []json.RawMessage{vmTrace}, nil)
+ gomock.Any(), utils.Mainnet, []*felt.Felt{}, false, false, gomock.Any(), gomock.Any(), false).Return(nil, []json.RawMessage{vmTrace}, nil)
trace, err := handler.TraceTransaction(context.Background(), *hash)
require.Nil(t, err)
@@ -2165,7 +2165,7 @@ func TestSimulateTransactions(t *testing.T) {
mockReader.EXPECT().HeadsHeader().Return(&core.Header{}, nil)
sequencerAddress := core.NetworkBlockHashMetaInfo(network).FallBackSequencerAddress
- mockVM.EXPECT().Execute(nil, nil, uint64(0), uint64(0), sequencerAddress, mockState, network, []*felt.Felt{}, true, false, nil, false).
+ mockVM.EXPECT().Execute(nil, nil, uint64(0), uint64(0), sequencerAddress, mockState, network, []*felt.Felt{}, true, false, nil, nil, false).
Return([]*felt.Felt{}, []json.RawMessage{}, nil)
_, err := handler.SimulateTransactions(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipFeeChargeFlag})
@@ -2180,7 +2180,7 @@ func TestSimulateTransactions(t *testing.T) {
mockReader.EXPECT().HeadsHeader().Return(&core.Header{}, nil)
sequencerAddress := core.NetworkBlockHashMetaInfo(network).FallBackSequencerAddress
- mockVM.EXPECT().Execute(nil, nil, uint64(0), uint64(0), sequencerAddress, mockState, network, []*felt.Felt{}, false, true, nil, false).
+ mockVM.EXPECT().Execute(nil, nil, uint64(0), uint64(0), sequencerAddress, mockState, network, []*felt.Felt{}, false, true, nil, nil, false).
Return([]*felt.Felt{}, []json.RawMessage{}, nil)
_, err := handler.SimulateTransactions(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipValidateFlag})
@@ -2249,7 +2249,7 @@ func TestTraceBlockTransactions(t *testing.T) {
"fee_transfer_invocation": {}
}`)
mockVM.EXPECT().Execute(block.Transactions, []core.Class{declaredClass.Class}, height+1, header.Timestamp, sequencerAddress,
- gomock.Any(), network, paidL1Fees, false, false, header.GasPrice, false).Return(nil, []json.RawMessage{vmTrace, vmTrace}, nil)
+ gomock.Any(), network, paidL1Fees, false, false, header.GasPrice, header.GasPriceSTRK, false).Return(nil, []json.RawMessage{vmTrace, vmTrace}, nil)
result, err := handler.TraceBlockTransactions(context.Background(), rpc.BlockID{Hash: blockHash})
require.Nil(t, err)
@@ -2293,7 +2293,7 @@ func TestTraceBlockTransactions(t *testing.T) {
"fee_transfer_invocation":{"entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x5dcd266a80b8a5f29f04d779c6b166b80150c24f2180a75e82427242dab20a9","0x15be","0x0"],"caller_address":"0xdac9bcffb3d967f19a7fe21002c98c984d5a9458a88e6fc5d1c478a97ed412","class_hash":"0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3","entry_point_type":"EXTERNAL","call_type":"CALL","result":["0x1"],"calls":[{"entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x5dcd266a80b8a5f29f04d779c6b166b80150c24f2180a75e82427242dab20a9","0x15be","0x0"],"caller_address":"0xdac9bcffb3d967f19a7fe21002c98c984d5a9458a88e6fc5d1c478a97ed412","class_hash":"0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0","entry_point_type":"EXTERNAL","call_type":"DELEGATE","result":["0x1"],"calls":[],"events":[{"keys":["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"],"data":["0xdac9bcffb3d967f19a7fe21002c98c984d5a9458a88e6fc5d1c478a97ed412","0x5dcd266a80b8a5f29f04d779c6b166b80150c24f2180a75e82427242dab20a9","0x15be","0x0"]}],"messages":[]}],"events":[],"messages":[]}}
}`)
mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, header.Number, header.Timestamp, header.SequencerAddress,
- gomock.Any(), network, []*felt.Felt{}, false, false, header.GasPrice, false).Return(nil, []json.RawMessage{vmTrace}, nil)
+ gomock.Any(), network, []*felt.Felt{}, false, false, header.GasPrice, header.GasPriceSTRK, false).Return(nil, []json.RawMessage{vmTrace}, nil)
expectedResult := []rpc.TracedBlockTransaction{
{
diff --git a/vm/rust/Cargo.toml b/vm/rust/Cargo.toml
index c2f3dc1417..97aa90245b 100644
--- a/vm/rust/Cargo.toml
+++ b/vm/rust/Cargo.toml
@@ -8,11 +8,11 @@ edition = "2021"
[dependencies]
serde = "1.0.171"
serde_json = { version = "1.0.96", features = ["raw_value"] }
-blockifier = {git = "https://github.com/starkware-libs/blockifier", rev = "v0.3.0-rc1"}
-starknet_api = { git = "https://github.com/starkware-libs/starknet-api", rev = "8f620bc" }
+blockifier = "0.4.0-rc8"
+starknet_api = "0.6.0-rc2"
cairo-vm = "0.8.2"
-cairo-lang-casm = "2.1.0"
-cairo-lang-starknet = "2.1.0"
+cairo-lang-casm = "2.4.0-rc2"
+cairo-lang-starknet = "2.4.0-rc2"
indexmap = "1.9.2"
starknet = { rev = "starknet-core/v0.4.0", git = "https://github.com/xJonathanLEI/starknet-rs" }
cached = "0.44.0"
diff --git a/vm/rust/src/jsonrpc.rs b/vm/rust/src/jsonrpc.rs
index 3c1bd359ea..86b1875ce4 100644
--- a/vm/rust/src/jsonrpc.rs
+++ b/vm/rust/src/jsonrpc.rs
@@ -1,13 +1,14 @@
use blockifier;
-use blockifier::execution::entry_point::{CallType, OrderedL2ToL1Message};
+use blockifier::execution::entry_point::CallType;
+use blockifier::execution::call_info::OrderedL2ToL1Message;
use blockifier::state::cached_state::TransactionalState;
use blockifier::state::errors::StateError;
use blockifier::state::state_api::{State, StateReader};
use serde::Serialize;
-use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, PatriciaKey};
+use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, PatriciaKey, EthAddress};
use starknet_api::deprecated_contract_class::EntryPointType;
use starknet_api::hash::StarkFelt;
-use starknet_api::transaction::{Calldata, EthAddress, EventContent, L2ToL1Payload};
+use starknet_api::transaction::{Calldata, EventContent, L2ToL1Payload};
use starknet_api::transaction::{DeclareTransaction, Transaction as StarknetApiTransaction};
use crate::juno_state_reader::JunoStateReader;
@@ -156,7 +157,7 @@ pub fn new_transaction_trace(
match declare_txn {
DeclareTransaction::V0(_) => Some(declare_txn.class_hash()),
DeclareTransaction::V1(_) => Some(declare_txn.class_hash()),
- DeclareTransaction::V2(_) => None,
+ _ => None,
}
} else {
None
@@ -180,7 +181,7 @@ pub struct OrderedEvent {
pub event: EventContent,
}
-type BlockifierOrderedEvent = blockifier::execution::entry_point::OrderedEvent;
+use blockifier::execution::call_info::OrderedEvent as BlockifierOrderedEvent;
impl From for OrderedEvent {
fn from(val: BlockifierOrderedEvent) -> Self {
OrderedEvent {
@@ -218,7 +219,7 @@ impl FunctionInvocation {
}
}
-type BlockifierCallInfo = blockifier::execution::entry_point::CallInfo;
+use blockifier::execution::call_info::CallInfo as BlockifierCallInfo;
impl From for FunctionInvocation {
fn from(val: BlockifierCallInfo) -> Self {
FunctionInvocation {
diff --git a/vm/rust/src/lib.rs b/vm/rust/src/lib.rs
index b81b380ba4..45a60d44b6 100644
--- a/vm/rust/src/lib.rs
+++ b/vm/rust/src/lib.rs
@@ -11,16 +11,17 @@ use std::{
use blockifier::{
abi::constants::{INITIAL_GAS_COST, N_STEPS_RESOURCE},
- block_context::BlockContext,
+ block_context::{BlockContext, GasPrices, FeeTokenAddresses},
execution::{
common_hints::ExecutionMode,
contract_class::{ContractClass, ContractClassV1},
entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext, ExecutionResources},
},
fee::fee_utils::calculate_tx_fee,
- state::cached_state::CachedState,
+ state::cached_state::{CachedState, GlobalContractCache},
transaction::{
- objects::AccountTransactionContext, transaction_execution::Transaction,
+ objects::{AccountTransactionContext, DeprecatedAccountTransactionContext, FeeType, HasRelatedFeeType},
+ transaction_execution::Transaction,
transactions::ExecutableTransaction,
},
};
@@ -33,7 +34,7 @@ use cairo_vm::vm::runners::builtin_runner::{
};
use juno_state_reader::{contract_class_from_json_str, felt_to_byte_array};
use serde::Deserialize;
-use starknet_api::transaction::{Calldata, Transaction as StarknetApiTransaction};
+use starknet_api::transaction::{Calldata, Transaction as StarknetApiTransaction, TransactionHash};
use starknet_api::{
block::{BlockNumber, BlockTimestamp},
deprecated_contract_class::EntryPointType,
@@ -98,24 +99,29 @@ pub extern "C" fn cairoVMCall(
initial_gas: INITIAL_GAS_COST,
};
- const GAS_PRICE: u128 = 1;
- let mut state = CachedState::new(reader);
+ const GAS_PRICES: GasPrices = GasPrices {
+ eth_l1_gas_price: 1,
+ strk_l1_gas_price: 1,
+ };
+ let mut state = CachedState::new(reader, GlobalContractCache::default());
let mut resources = ExecutionResources::default();
- let mut context = EntryPointExecutionContext::new(
- build_block_context(
+ let context = EntryPointExecutionContext::new(
+ &build_block_context(
chain_id_str,
block_number,
block_timestamp,
StarkFelt::default(),
- GAS_PRICE,
+ GAS_PRICES,
),
- AccountTransactionContext::default(),
- 4_000_000,
+ &AccountTransactionContext::Deprecated(DeprecatedAccountTransactionContext::default()),
ExecutionMode::Execute,
+ false,
);
- let call_info = entry_point.execute(&mut state, &mut resources, &mut context);
-
- match call_info {
+ if let Err(e) = context {
+ report_error(reader_handle, e.to_string().as_str());
+ return;
+ }
+ match entry_point.execute(&mut state, &mut resources, &mut context.unwrap()) {
Err(e) => report_error(reader_handle, e.to_string().as_str()),
Ok(t) => {
for data in t.execution.retdata.0 {
@@ -130,6 +136,7 @@ pub extern "C" fn cairoVMCall(
#[derive(Deserialize)]
pub struct TxnAndQueryBit {
pub txn: StarknetApiTransaction,
+ pub txn_hash: TransactionHash,
pub query_bit: bool,
}
@@ -145,7 +152,8 @@ pub extern "C" fn cairoVMExecute(
paid_fees_on_l1_json: *const c_char,
skip_charge_fee: c_uchar,
skip_validate: c_uchar,
- gas_price: *const c_uchar,
+ gas_price_wei: *const c_uchar,
+ gas_price_strk: *const c_uchar,
legacy_json: c_uchar,
) {
let reader = JunoStateReader::new(reader_handle, block_number);
@@ -183,15 +191,19 @@ pub extern "C" fn cairoVMExecute(
let mut classes = classes.unwrap();
let sequencer_address_felt = ptr_to_felt(sequencer_address);
- let gas_price_felt = ptr_to_felt(gas_price);
+ let gas_price_wei_felt = ptr_to_felt(gas_price_wei);
+ let gas_price_strk_felt = ptr_to_felt(gas_price_strk);
let block_context: BlockContext = build_block_context(
chain_id_str,
block_number,
block_timestamp,
sequencer_address_felt,
- felt_to_u128(gas_price_felt),
+ GasPrices {
+ eth_l1_gas_price: felt_to_u128(gas_price_wei_felt),
+ strk_l1_gas_price: felt_to_u128(gas_price_strk_felt),
+ },
);
- let mut state = CachedState::new(reader);
+ let mut state = CachedState::new(reader, GlobalContractCache::default());
let charge_fee = skip_charge_fee == 0;
let validate = skip_validate == 0;
@@ -234,6 +246,7 @@ pub extern "C" fn cairoVMExecute(
let txn = transaction_from_api(
txn_and_query_bit.txn.clone(),
+ txn_and_query_bit.txn_hash,
contract_class,
paid_fee_on_l1,
txn_and_query_bit.query_bit,
@@ -244,11 +257,14 @@ pub extern "C" fn cairoVMExecute(
}
let mut txn_state = CachedState::create_transactional(&mut state);
+ let mut fee_type = FeeType::Eth;
let res = match txn.unwrap() {
Transaction::AccountTransaction(t) => {
+ fee_type = t.fee_type();
t.execute(&mut txn_state, &block_context, charge_fee, validate)
}
Transaction::L1HandlerTransaction(t) => {
+ fee_type = t.fee_type();
t.execute(&mut txn_state, &block_context, charge_fee, validate)
}
};
@@ -259,7 +275,7 @@ pub extern "C" fn cairoVMExecute(
reader_handle,
format!(
"failed txn {:?} reason:{:?}",
- txn_and_query_bit.txn.transaction_hash(),
+ txn_and_query_bit.txn_hash,
e
)
.as_str(),
@@ -269,7 +285,7 @@ pub extern "C" fn cairoVMExecute(
Ok(mut t) => {
// we are estimating fee, override actual fee calculation
if !charge_fee {
- t.actual_fee = calculate_tx_fee(&t.actual_resources, &block_context).unwrap();
+ t.actual_fee = calculate_tx_fee(&t.actual_resources, &block_context, &fee_type).unwrap();
}
let actual_fee = t.actual_fee.0.into();
@@ -311,27 +327,28 @@ fn felt_to_u128(felt: StarkFelt) -> u128 {
fn transaction_from_api(
tx: StarknetApiTransaction,
+ tx_hash: TransactionHash,
contract_class: Option,
paid_fee_on_l1: Option,
query_bit: bool,
) -> Result {
match tx {
- StarknetApiTransaction::Deploy(deploy) => {
+ StarknetApiTransaction::Deploy(_) => {
return Err(format!(
"Unsupported deploy transaction in the traced block (transaction_hash={})",
- deploy.transaction_hash
+ tx_hash,
))
}
- StarknetApiTransaction::Declare(declare) if contract_class.is_none() => {
+ StarknetApiTransaction::Declare(_) if contract_class.is_none() => {
return Err(format!(
"Declare transaction must be created with a ContractClass (transaction_hash={})",
- declare.transaction_hash()
+ tx_hash,
))
}
_ => {} // all ok
};
- Transaction::from_api(tx, contract_class, paid_fee_on_l1, query_bit)
+ Transaction::from_api(tx, tx_hash, contract_class, paid_fee_on_l1, None, query_bit)
.map_err(|err| format!("failed to create transaction from api: {:?}", err))
}
@@ -363,7 +380,7 @@ fn build_block_context(
block_number: c_ulonglong,
block_timestamp: c_ulonglong,
sequencer_address: StarkFelt,
- gas_price: u128,
+ gas_prices: GasPrices,
) -> BlockContext {
BlockContext {
chain_id: ChainId(chain_id_str.into()),
@@ -372,15 +389,12 @@ fn build_block_context(
sequencer_address: ContractAddress::try_from(sequencer_address).unwrap(),
// https://github.com/starknet-io/starknet-addresses/blob/df19b17d2c83f11c30e65e2373e8a0c65446f17c/bridged_tokens/mainnet.json
- // fee_token_address is the same for all networks
- fee_token_address: ContractAddress::try_from(
- StarkHash::try_from(
- "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
- )
- .unwrap(),
- )
- .unwrap(),
- gas_price, // fixed gas price, so that we can return "consumed gas" to Go side
+ fee_token_addresses: FeeTokenAddresses {
+ // both addresses are the same for all networks
+ eth_fee_token_address: ContractAddress::try_from(StarkHash::try_from("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap()).unwrap(),
+ strk_fee_token_address: ContractAddress::try_from(StarkHash::try_from("0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d").unwrap()).unwrap(),
+ },
+ gas_prices, // fixed gas price, so that we can return "consumed gas" to Go side
vm_resource_fee_cost: HashMap::from([
(N_STEPS_RESOURCE.to_string(), N_STEPS_FEE_WEIGHT),
(OUTPUT_BUILTIN_NAME.to_string(), 0.0),
diff --git a/vm/transaction.go b/vm/transaction.go
index 6f8014966b..bcd3ac087d 100644
--- a/vm/transaction.go
+++ b/vm/transaction.go
@@ -22,7 +22,8 @@ func marshalTxn(txn core.Transaction) (json.RawMessage, error) {
txnAndQueryBit := struct {
QueryBit bool `json:"query_bit"`
Txn map[string]any `json:"txn"`
- }{Txn: make(map[string]any), QueryBit: version.HasQueryBit()}
+ TxnHash *felt.Felt `json:"txn_hash"`
+ }{Txn: make(map[string]any), QueryBit: version.HasQueryBit(), TxnHash: t.Hash}
versionWithoutQueryBit := version.WithoutQueryBit()
t.Version = versionWithoutQueryBit.AsFelt()
@@ -37,7 +38,9 @@ func marshalTxn(txn core.Transaction) (json.RawMessage, error) {
"V" + t.Version.Text(felt.Base10): t,
}
case *core.DeployAccountTransaction:
- txnAndQueryBit.Txn["DeployAccount"] = t
+ txnAndQueryBit.Txn["DeployAccount"] = map[string]any{
+ "V" + t.Version.Text(felt.Base10): t,
+ }
case *core.DeclareTransaction:
txnAndQueryBit.Txn["Declare"] = map[string]any{
"V" + t.Version.Text(felt.Base10): t,
diff --git a/vm/vm.go b/vm/vm.go
index f8e10ede25..8c26a4225c 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -9,7 +9,7 @@ package vm
//
// extern void cairoVMExecute(char* txns_json, char* classes_json, uintptr_t readerHandle, unsigned long long block_number,
// unsigned long long block_timestamp, char* chain_id, char* sequencer_address, char* paid_fees_on_l1_json,
-// unsigned char skip_charge_fee, unsigned char skip_validate, char* gas_price, unsigned char legacy_json);
+// unsigned char skip_charge_fee, unsigned char skip_validate, char* gas_price_wei, char* gas_price_strk, unsigned char legacy_json);
//
// #cgo vm_debug LDFLAGS: -L./rust/target/debug -ljuno_starknet_rs -lm -ldl
// #cgo !vm_debug LDFLAGS: -L./rust/target/release -ljuno_starknet_rs -lm -ldl
@@ -33,7 +33,7 @@ type VM interface {
) ([]*felt.Felt, error)
Execute(txns []core.Transaction, declaredClasses []core.Class, blockNumber, blockTimestamp uint64,
sequencerAddress *felt.Felt, state core.StateReader, network utils.Network, paidFeesOnL1 []*felt.Felt,
- skipChargeFee, skipValidate bool, gasPrice *felt.Felt, legacyTraceJSON bool,
+ skipChargeFee, skipValidate bool, gasPriceWEI *felt.Felt, gasPriceSTRK *felt.Felt, legacyTraceJSON bool,
) ([]*felt.Felt, []json.RawMessage, error)
}
@@ -143,7 +143,8 @@ func (v *vm) Call(contractAddr, classHash, selector *felt.Felt, calldata []felt.
C.uintptr_t(handle),
C.ulonglong(blockNumber),
C.ulonglong(blockTimestamp),
- chainID)
+ chainID,
+ )
for _, ptr := range calldataPtrs {
C.free(unsafe.Pointer(ptr))
@@ -159,7 +160,7 @@ func (v *vm) Call(contractAddr, classHash, selector *felt.Felt, calldata []felt.
// Execute executes a given transaction set and returns the gas spent per transaction
func (v *vm) Execute(txns []core.Transaction, declaredClasses []core.Class, blockNumber, blockTimestamp uint64,
sequencerAddress *felt.Felt, state core.StateReader, network utils.Network, paidFeesOnL1 []*felt.Felt,
- skipChargeFee, skipValidate bool, gasPrice *felt.Felt, legacyTraceJSON bool,
+ skipChargeFee, skipValidate bool, gasPriceWEI *felt.Felt, gasPriceSTRK *felt.Felt, legacyTraceJSON bool,
) ([]*felt.Felt, []json.RawMessage, error) {
context := &callContext{
state: state,
@@ -183,7 +184,12 @@ func (v *vm) Execute(txns []core.Transaction, declaredClasses []core.Class, bloc
classesJSONCStr := cstring(classesJSON)
sequencerAddressBytes := sequencerAddress.Bytes()
- gasPriceBytes := gasPrice.Bytes()
+ gasPriceWEIBytes := gasPriceWEI.Bytes()
+
+ if gasPriceSTRK == nil {
+ gasPriceSTRK = &felt.Zero
+ }
+ gasPriceSTRKBytes := gasPriceSTRK.Bytes()
var skipChargeFeeByte byte
if skipChargeFee {
@@ -211,7 +217,8 @@ func (v *vm) Execute(txns []core.Transaction, declaredClasses []core.Class, bloc
paidFeesOnL1CStr,
C.uchar(skipChargeFeeByte),
C.uchar(skipValidateByte),
- (*C.char)(unsafe.Pointer(&gasPriceBytes[0])),
+ (*C.char)(unsafe.Pointer(&gasPriceWEIBytes[0])),
+ (*C.char)(unsafe.Pointer(&gasPriceSTRKBytes[0])),
C.uchar(legacyTraceJSONByte),
)
diff --git a/vm/vm_test.go b/vm/vm_test.go
index fd2a616cb1..2226606598 100644
--- a/vm/vm_test.go
+++ b/vm/vm_test.go
@@ -158,11 +158,11 @@ func TestExecute(t *testing.T) {
address = utils.HexToFelt(t, "0x46a89ae102987331d369645031b49c27738ed096f2789c24449966da4c6de6b")
timestamp = uint64(1666877926)
)
- _, _, err := New(nil).Execute([]core.Transaction{}, []core.Class{}, 0, timestamp, address, state, network, []*felt.Felt{}, false, false, &felt.Zero, false)
+ _, _, err := New(nil).Execute([]core.Transaction{}, []core.Class{}, 0, timestamp, address, state, network, []*felt.Felt{}, false, false, &felt.Zero, &felt.Zero, false)
require.NoError(t, err)
})
t.Run("zero data", func(t *testing.T) {
- _, _, err := New(nil).Execute(nil, nil, 0, 0, &felt.Zero, state, network, []*felt.Felt{}, false, false, &felt.Zero, false)
+ _, _, err := New(nil).Execute(nil, nil, 0, 0, &felt.Zero, state, network, []*felt.Felt{}, false, false, &felt.Zero, &felt.Zero, false)
require.NoError(t, err)
})
}