mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
fix (libzkp): check tx num when CCC ErrUnknown error occurred (#505)
* Check tx num for CCC ErrUnknown error. * Update worker.go * Small fix. * Update * Fix log. * Update version. * Update miner/worker.go Co-authored-by: Péter Garamvölgyi <peter@scroll.io> * Update according to review. * Fix to return 0 for uint64. * Add `tcount` to mock CCC, and function `SetTxNum`. * refactor * fix * add comments --------- Co-authored-by: Zhang Zhuo <mycinbrin@gmail.com> Co-authored-by: Péter Garamvölgyi <peter@scroll.io> Co-authored-by: HAOYUatHZ <haoyu@protonmail.com>
This commit is contained in:
parent
dade96d416
commit
7d79f27e6f
7 changed files with 112 additions and 1 deletions
|
|
@ -1145,6 +1145,7 @@ loop:
|
|||
// However, after `ErrUnknown`, ccc might remain in an
|
||||
// inconsistent state, so we cannot pack more transactions.
|
||||
circuitCapacityReached = true
|
||||
w.checkCurrentTxNumWithCCC(w.current.tcount)
|
||||
break loop
|
||||
|
||||
case (errors.Is(err, circuitcapacitychecker.ErrUnknown) && !tx.IsL1MessageTx()):
|
||||
|
|
@ -1164,6 +1165,7 @@ loop:
|
|||
// inconsistent state, so we cannot pack more transactions.
|
||||
w.eth.TxPool().RemoveTx(tx.Hash(), true)
|
||||
circuitCapacityReached = true
|
||||
w.checkCurrentTxNumWithCCC(w.current.tcount)
|
||||
break loop
|
||||
|
||||
default:
|
||||
|
|
@ -1208,6 +1210,17 @@ loop:
|
|||
return false, circuitCapacityReached
|
||||
}
|
||||
|
||||
func (w *worker) checkCurrentTxNumWithCCC(expected int) {
|
||||
match, got, err := w.circuitCapacityChecker.CheckTxNum(expected)
|
||||
if err != nil {
|
||||
log.Error("failed to CheckTxNum in ccc", "err", err)
|
||||
return
|
||||
}
|
||||
if !match {
|
||||
log.Error("tx count in miner is different with CCC", "w.current.tcount", w.current.tcount, "got", got)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worker) collectPendingL1Messages(startIndex uint64) []types.L1MessageTx {
|
||||
maxCount := w.chainConfig.Scroll.L1Config.NumL1MessagesPerBlock
|
||||
return rawdb.ReadL1MessagesFrom(w.eth.ChainDb(), startIndex, maxCount)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
const (
|
||||
VersionMajor = 4 // Major version component of the current release
|
||||
VersionMinor = 4 // Minor version component of the current release
|
||||
VersionPatch = 2 // Patch version component of the current release
|
||||
VersionPatch = 3 // Patch version component of the current release
|
||||
VersionMeta = "sepolia" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ type CircuitCapacityChecker struct {
|
|||
ID uint64
|
||||
}
|
||||
|
||||
// NewCircuitCapacityChecker creates a new CircuitCapacityChecker
|
||||
func NewCircuitCapacityChecker() *CircuitCapacityChecker {
|
||||
creationMu.Lock()
|
||||
defer creationMu.Unlock()
|
||||
|
|
@ -39,6 +40,7 @@ func NewCircuitCapacityChecker() *CircuitCapacityChecker {
|
|||
return &CircuitCapacityChecker{ID: uint64(id)}
|
||||
}
|
||||
|
||||
// Reset resets a CircuitCapacityChecker
|
||||
func (ccc *CircuitCapacityChecker) Reset() {
|
||||
ccc.Lock()
|
||||
defer ccc.Unlock()
|
||||
|
|
@ -46,6 +48,7 @@ func (ccc *CircuitCapacityChecker) Reset() {
|
|||
C.reset_circuit_capacity_checker(C.uint64_t(ccc.ID))
|
||||
}
|
||||
|
||||
// ApplyTransaction appends a tx's wrapped BlockTrace into the ccc, and return the accumulated RowConsumption
|
||||
func (ccc *CircuitCapacityChecker) ApplyTransaction(traces *types.BlockTrace) (*types.RowConsumption, error) {
|
||||
ccc.Lock()
|
||||
defer ccc.Unlock()
|
||||
|
|
@ -100,6 +103,7 @@ func (ccc *CircuitCapacityChecker) ApplyTransaction(traces *types.BlockTrace) (*
|
|||
return (*types.RowConsumption)(&result.AccRowUsage.RowUsageDetails), nil
|
||||
}
|
||||
|
||||
// ApplyBlock gets a block's RowConsumption
|
||||
func (ccc *CircuitCapacityChecker) ApplyBlock(traces *types.BlockTrace) (*types.RowConsumption, error) {
|
||||
ccc.Lock()
|
||||
defer ccc.Unlock()
|
||||
|
|
@ -141,3 +145,28 @@ func (ccc *CircuitCapacityChecker) ApplyBlock(traces *types.BlockTrace) (*types.
|
|||
}
|
||||
return (*types.RowConsumption)(&result.AccRowUsage.RowUsageDetails), nil
|
||||
}
|
||||
|
||||
// CheckTxNum compares whether the tx_count in ccc match the expected
|
||||
func (ccc *CircuitCapacityChecker) CheckTxNum(expected int) (bool, unit64, error) {
|
||||
ccc.Lock()
|
||||
defer ccc.Unlock()
|
||||
|
||||
log.Debug("ccc get_tx_num start", "id", ccc.ID)
|
||||
rawResult := C.get_tx_num(C.uint64_t(ccc.ID))
|
||||
defer func() {
|
||||
C.free(unsafe.Pointer(rawResult))
|
||||
}()
|
||||
log.Debug("ccc get_tx_num end", "id", ccc.ID)
|
||||
|
||||
result := &WrappedTxNum{}
|
||||
if err = json.Unmarshal([]byte(C.GoString(rawResult)), result); err != nil {
|
||||
log.Error("fail to json unmarshal get_tx_num result", "id", ccc.ID, "err", err)
|
||||
return false, 0, ErrUnknown
|
||||
}
|
||||
if result.Error != "" {
|
||||
log.Error("fail to get_tx_num in CircuitCapacityChecker", "id", ccc.ID, "err", result.Error)
|
||||
return false, 0, ErrUnknown
|
||||
}
|
||||
|
||||
return result.TxNum == unit64(expected), result.TxNum, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ uint64_t new_circuit_capacity_checker();
|
|||
void reset_circuit_capacity_checker(uint64_t id);
|
||||
char* apply_tx(uint64_t id, char *tx_traces);
|
||||
char* apply_block(uint64_t id, char *block_trace);
|
||||
char* get_tx_num(uint64_t id);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@ pub mod checker {
|
|||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct TxNumResult {
|
||||
pub tx_num: u64,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
static mut CHECKERS: OnceCell<HashMap<u64, CircuitCapacityChecker>> = OnceCell::new();
|
||||
|
||||
/// # Safety
|
||||
|
|
@ -176,6 +182,50 @@ pub mod checker {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_tx_num(id: u64) -> *const c_char {
|
||||
let result = get_tx_num_inner(id);
|
||||
let r = match result {
|
||||
Ok(tx_num) => {
|
||||
log::debug!("id: {id}, tx_num: {tx_num}");
|
||||
TxNumResult {
|
||||
tx_num,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
Err(e) => TxNumResult {
|
||||
tx_num: 0,
|
||||
error: Some(format!("{e:?}")),
|
||||
},
|
||||
};
|
||||
serde_json::to_vec(&r).map_or(null(), vec_to_c_char)
|
||||
}
|
||||
|
||||
unsafe fn get_tx_num_inner(id: u64) -> Result<u64, Error> {
|
||||
log::debug!("ccc get_tx_num raw input, id: {id}");
|
||||
panic::catch_unwind(|| {
|
||||
Ok(CHECKERS
|
||||
.get_mut()
|
||||
.ok_or(anyhow!(
|
||||
"fail to get circuit capacity checkers map in get_tx_num"
|
||||
))?
|
||||
.get_mut(&id)
|
||||
.ok_or(anyhow!(
|
||||
"fail to get circuit capacity checker (id: {id}) in get_tx_num"
|
||||
))?
|
||||
.get_tx_num() as u64)
|
||||
})
|
||||
.map_or_else(
|
||||
|e| {
|
||||
Err(anyhow!(
|
||||
"circuit capacity checker (id: {id}) error in get_tx_num: {e:?}"
|
||||
))
|
||||
},
|
||||
|result| result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod utils {
|
||||
|
|
|
|||
|
|
@ -14,13 +14,17 @@ type CircuitCapacityChecker struct {
|
|||
nextError *error
|
||||
}
|
||||
|
||||
// NewCircuitCapacityChecker creates a new CircuitCapacityChecker
|
||||
func NewCircuitCapacityChecker() *CircuitCapacityChecker {
|
||||
return &CircuitCapacityChecker{ID: rand.Uint64()}
|
||||
}
|
||||
|
||||
// Reset resets a ccc, but need to do nothing in mock_ccc.
|
||||
func (ccc *CircuitCapacityChecker) Reset() {
|
||||
}
|
||||
|
||||
// ApplyTransaction appends a tx's wrapped BlockTrace into the ccc, and return the accumulated RowConsumption.
|
||||
// Will only return a dummy value in mock_ccc.
|
||||
func (ccc *CircuitCapacityChecker) ApplyTransaction(traces *types.BlockTrace) (*types.RowConsumption, error) {
|
||||
if ccc.nextError != nil {
|
||||
ccc.countdown--
|
||||
|
|
@ -36,6 +40,8 @@ func (ccc *CircuitCapacityChecker) ApplyTransaction(traces *types.BlockTrace) (*
|
|||
}}, nil
|
||||
}
|
||||
|
||||
// ApplyBlock gets a block's RowConsumption.
|
||||
// Will only return a dummy value in mock_ccc.
|
||||
func (ccc *CircuitCapacityChecker) ApplyBlock(traces *types.BlockTrace) (*types.RowConsumption, error) {
|
||||
return &types.RowConsumption{types.SubCircuitRowUsage{
|
||||
Name: "mock",
|
||||
|
|
@ -43,6 +49,13 @@ func (ccc *CircuitCapacityChecker) ApplyBlock(traces *types.BlockTrace) (*types.
|
|||
}}, nil
|
||||
}
|
||||
|
||||
// CheckTxNum compares whether the tx_count in ccc match the expected.
|
||||
// Will alway return true in mock_ccc.
|
||||
func (ccc *CircuitCapacityChecker) CheckTxNum(expected int) (bool, uint64, error) {
|
||||
return true, uint64(expected), nil
|
||||
}
|
||||
|
||||
// ScheduleError schedules an error for a tx (see `ApplyTransaction`), only used in tests.
|
||||
func (ccc *CircuitCapacityChecker) ScheduleError(cnt int, err error) {
|
||||
ccc.countdown = cnt
|
||||
ccc.nextError = &err
|
||||
|
|
|
|||
|
|
@ -15,3 +15,8 @@ type WrappedRowUsage struct {
|
|||
AccRowUsage *types.RowUsage `json:"acc_row_usage,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type WrappedTxNum struct {
|
||||
TxNum uint64 `json:"tx_num"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue