github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/rollup/circuitcapacitychecker/impl.go (about)

     1  //go:build circuit_capacity_checker
     2  
     3  package circuitcapacitychecker
     4  
     5  /*
     6  #cgo LDFLAGS: -lm -ldl -lzkp -lzktrie
     7  #include <stdlib.h>
     8  #include "./libzkp/libzkp.h"
     9  */
    10  import "C" //nolint:typecheck
    11  
    12  import (
    13  	"encoding/json"
    14  	"fmt"
    15  	"sync"
    16  	"unsafe"
    17  
    18  	"github.com/scroll-tech/go-ethereum/core/types"
    19  	"github.com/scroll-tech/go-ethereum/log"
    20  )
    21  
    22  // mutex for concurrent CircuitCapacityChecker creations
    23  var creationMu sync.Mutex
    24  
    25  func init() {
    26  	C.init()
    27  }
    28  
    29  type CircuitCapacityChecker struct {
    30  	// mutex for each CircuitCapacityChecker itself
    31  	sync.Mutex
    32  	ID uint64
    33  }
    34  
    35  // NewCircuitCapacityChecker creates a new CircuitCapacityChecker
    36  func NewCircuitCapacityChecker(lightMode bool) *CircuitCapacityChecker {
    37  	creationMu.Lock()
    38  	defer creationMu.Unlock()
    39  
    40  	id := C.new_circuit_capacity_checker()
    41  	ccc := &CircuitCapacityChecker{ID: uint64(id)}
    42  	ccc.SetLightMode(lightMode)
    43  	return ccc
    44  }
    45  
    46  // Reset resets a CircuitCapacityChecker
    47  func (ccc *CircuitCapacityChecker) Reset() {
    48  	ccc.Lock()
    49  	defer ccc.Unlock()
    50  
    51  	C.reset_circuit_capacity_checker(C.uint64_t(ccc.ID))
    52  }
    53  
    54  // ApplyTransaction appends a tx's wrapped BlockTrace into the ccc, and return the accumulated RowConsumption
    55  func (ccc *CircuitCapacityChecker) ApplyTransaction(traces *types.BlockTrace) (*types.RowConsumption, error) {
    56  	ccc.Lock()
    57  	defer ccc.Unlock()
    58  
    59  	if len(traces.Transactions) != 1 || len(traces.ExecutionResults) != 1 || len(traces.TxStorageTraces) != 1 {
    60  		log.Error("malformatted BlockTrace in ApplyTransaction", "id", ccc.ID,
    61  			"len(traces.Transactions)", len(traces.Transactions),
    62  			"len(traces.ExecutionResults)", len(traces.ExecutionResults),
    63  			"len(traces.TxStorageTraces)", len(traces.TxStorageTraces),
    64  			"err", "length of Transactions, or ExecutionResults, or TxStorageTraces, is not equal to 1")
    65  		return nil, ErrUnknown
    66  	}
    67  
    68  	tracesByt, err := json.Marshal(traces)
    69  	if err != nil {
    70  		log.Error("fail to json marshal traces in ApplyTransaction", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash, "err", err)
    71  		return nil, ErrUnknown
    72  	}
    73  
    74  	tracesStr := C.CString(string(tracesByt))
    75  	defer func() {
    76  		C.free(unsafe.Pointer(tracesStr))
    77  	}()
    78  
    79  	log.Debug("start to check circuit capacity for tx", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash)
    80  	rawResult := C.apply_tx(C.uint64_t(ccc.ID), tracesStr)
    81  	defer func() {
    82  		C.free_c_chars(rawResult)
    83  	}()
    84  	log.Debug("check circuit capacity for tx done", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash)
    85  
    86  	result := &WrappedRowUsage{}
    87  	if err = json.Unmarshal([]byte(C.GoString(rawResult)), result); err != nil {
    88  		log.Error("fail to json unmarshal apply_tx result", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash, "err", err)
    89  		return nil, ErrUnknown
    90  	}
    91  
    92  	if result.Error != "" {
    93  		log.Error("fail to apply_tx in CircuitCapacityChecker", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash, "err", result.Error)
    94  		return nil, ErrUnknown
    95  	}
    96  	if result.AccRowUsage == nil {
    97  		log.Error("fail to apply_tx in CircuitCapacityChecker",
    98  			"id", ccc.ID, "TxHash", traces.Transactions[0].TxHash,
    99  			"result.AccRowUsage == nil", result.AccRowUsage == nil,
   100  			"err", "AccRowUsage is empty unexpectedly")
   101  		return nil, ErrUnknown
   102  	}
   103  	if !result.AccRowUsage.IsOk {
   104  		return nil, ErrBlockRowConsumptionOverflow
   105  	}
   106  	return (*types.RowConsumption)(&result.AccRowUsage.RowUsageDetails), nil
   107  }
   108  
   109  // ApplyBlock gets a block's RowConsumption
   110  func (ccc *CircuitCapacityChecker) ApplyBlock(traces *types.BlockTrace) (*types.RowConsumption, error) {
   111  	ccc.Lock()
   112  	defer ccc.Unlock()
   113  
   114  	tracesByt, err := json.Marshal(traces)
   115  	if err != nil {
   116  		log.Error("fail to json marshal traces in ApplyBlock", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash(), "err", err)
   117  		return nil, ErrUnknown
   118  	}
   119  
   120  	tracesStr := C.CString(string(tracesByt))
   121  	defer func() {
   122  		C.free(unsafe.Pointer(tracesStr))
   123  	}()
   124  
   125  	log.Debug("start to check circuit capacity for block", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash())
   126  	rawResult := C.apply_block(C.uint64_t(ccc.ID), tracesStr)
   127  	defer func() {
   128  		C.free_c_chars(rawResult)
   129  	}()
   130  	log.Debug("check circuit capacity for block done", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash())
   131  
   132  	result := &WrappedRowUsage{}
   133  	if err = json.Unmarshal([]byte(C.GoString(rawResult)), result); err != nil {
   134  		log.Error("fail to json unmarshal apply_block result", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash(), "err", err)
   135  		return nil, ErrUnknown
   136  	}
   137  
   138  	if result.Error != "" {
   139  		log.Error("fail to apply_block in CircuitCapacityChecker", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash(), "err", result.Error)
   140  		return nil, ErrUnknown
   141  	}
   142  	if result.AccRowUsage == nil {
   143  		log.Error("fail to apply_block in CircuitCapacityChecker", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash(), "err", "AccRowUsage is empty unexpectedly")
   144  		return nil, ErrUnknown
   145  	}
   146  	if !result.AccRowUsage.IsOk {
   147  		return nil, ErrBlockRowConsumptionOverflow
   148  	}
   149  	return (*types.RowConsumption)(&result.AccRowUsage.RowUsageDetails), nil
   150  }
   151  
   152  // CheckTxNum compares whether the tx_count in ccc match the expected
   153  func (ccc *CircuitCapacityChecker) CheckTxNum(expected int) (bool, uint64, error) {
   154  	ccc.Lock()
   155  	defer ccc.Unlock()
   156  
   157  	log.Debug("ccc get_tx_num start", "id", ccc.ID)
   158  	rawResult := C.get_tx_num(C.uint64_t(ccc.ID))
   159  	defer func() {
   160  		C.free_c_chars(rawResult)
   161  	}()
   162  	log.Debug("ccc get_tx_num end", "id", ccc.ID)
   163  
   164  	result := &WrappedTxNum{}
   165  	if err := json.Unmarshal([]byte(C.GoString(rawResult)), result); err != nil {
   166  		return false, 0, fmt.Errorf("fail to json unmarshal get_tx_num result, id: %d, err: %w", ccc.ID, err)
   167  	}
   168  	if result.Error != "" {
   169  		return false, 0, fmt.Errorf("fail to get_tx_num in CircuitCapacityChecker, id: %d, err: %w", ccc.ID, result.Error)
   170  	}
   171  
   172  	return result.TxNum == uint64(expected), result.TxNum, nil
   173  }
   174  
   175  // SetLightMode sets to ccc light mode
   176  func (ccc *CircuitCapacityChecker) SetLightMode(lightMode bool) error {
   177  	ccc.Lock()
   178  	defer ccc.Unlock()
   179  
   180  	log.Debug("ccc set_light_mode start", "id", ccc.ID)
   181  	rawResult := C.set_light_mode(C.uint64_t(ccc.ID), C.bool(lightMode))
   182  	defer func() {
   183  		C.free_c_chars(rawResult)
   184  	}()
   185  	log.Debug("ccc set_light_mode end", "id", ccc.ID)
   186  
   187  	result := &WrappedCommonResult{}
   188  	if err := json.Unmarshal([]byte(C.GoString(rawResult)), result); err != nil {
   189  		return fmt.Errorf("fail to json unmarshal set_light_mode result, id: %d, err: %w", ccc.ID, err)
   190  	}
   191  	if result.Error != "" {
   192  		return fmt.Errorf("fail to set_light_mode in CircuitCapacityChecker, id: %d, err: %w", ccc.ID, result.Error)
   193  	}
   194  
   195  	return nil
   196  }