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 }