github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/state/converters.go (about) 1 package state 2 3 import ( 4 "context" 5 "fmt" 6 "math/big" 7 "time" 8 9 "github.com/0xPolygon/supernets2-node/encoding" 10 "github.com/0xPolygon/supernets2-node/event" 11 "github.com/0xPolygon/supernets2-node/hex" 12 "github.com/0xPolygon/supernets2-node/log" 13 "github.com/0xPolygon/supernets2-node/state/runtime/executor" 14 "github.com/0xPolygon/supernets2-node/state/runtime/executor/pb" 15 "github.com/0xPolygon/supernets2-node/state/runtime/fakevm" 16 "github.com/0xPolygon/supernets2-node/state/runtime/instrumentation" 17 "github.com/ethereum/go-ethereum/common" 18 "github.com/ethereum/go-ethereum/core/types" 19 ) 20 21 // ConvertToCounters extracts ZKCounters from a ProcessBatchResponse 22 func ConvertToCounters(resp *pb.ProcessBatchResponse) ZKCounters { 23 return ZKCounters{ 24 CumulativeGasUsed: resp.CumulativeGasUsed, 25 UsedKeccakHashes: resp.CntKeccakHashes, 26 UsedPoseidonHashes: resp.CntPoseidonHashes, 27 UsedPoseidonPaddings: resp.CntPoseidonPaddings, 28 UsedMemAligns: resp.CntMemAligns, 29 UsedArithmetics: resp.CntArithmetics, 30 UsedBinaries: resp.CntBinaries, 31 UsedSteps: resp.CntSteps, 32 } 33 } 34 35 // TestConvertToProcessBatchResponse for test purposes 36 func (s *State) TestConvertToProcessBatchResponse(txs []types.Transaction, response *pb.ProcessBatchResponse) (*ProcessBatchResponse, error) { 37 return s.convertToProcessBatchResponse(txs, response) 38 } 39 40 func (s *State) convertToProcessBatchResponse(txs []types.Transaction, response *pb.ProcessBatchResponse) (*ProcessBatchResponse, error) { 41 responses, err := s.convertToProcessTransactionResponse(txs, response.Responses) 42 if err != nil { 43 return nil, err 44 } 45 46 readWriteAddresses, err := convertToReadWriteAddresses(response.ReadWriteAddresses) 47 if err != nil { 48 return nil, err 49 } 50 51 isExecutorLevelError := (response.Error != executor.EXECUTOR_ERROR_NO_ERROR) 52 isRomLevelError := false 53 isRomOOCError := false 54 55 if response.Responses != nil { 56 for _, resp := range response.Responses { 57 if resp.Error != pb.RomError_ROM_ERROR_NO_ERROR { 58 isRomLevelError = true 59 break 60 } 61 } 62 63 if len(response.Responses) > 0 { 64 // Check out of counters 65 errorToCheck := response.Responses[len(response.Responses)-1].Error 66 isRomOOCError = executor.IsROMOutOfCountersError(errorToCheck) 67 } 68 } 69 70 return &ProcessBatchResponse{ 71 NewStateRoot: common.BytesToHash(response.NewStateRoot), 72 NewAccInputHash: common.BytesToHash(response.NewAccInputHash), 73 NewLocalExitRoot: common.BytesToHash(response.NewLocalExitRoot), 74 NewBatchNumber: response.NewBatchNum, 75 UsedZkCounters: convertToCounters(response), 76 Responses: responses, 77 ExecutorError: executor.ExecutorErr(response.Error), 78 IsExecutorLevelError: isExecutorLevelError, 79 IsRomLevelError: isRomLevelError, 80 IsRomOOCError: isRomOOCError, 81 ReadWriteAddresses: readWriteAddresses, 82 }, nil 83 } 84 85 // IsStateRootChanged returns true if the transaction changes the state root 86 func IsStateRootChanged(err pb.RomError) bool { 87 return !executor.IsIntrinsicError(err) && !executor.IsROMOutOfCountersError(err) 88 } 89 90 func convertToReadWriteAddresses(addresses map[string]*pb.InfoReadWrite) (map[common.Address]*InfoReadWrite, error) { 91 results := make(map[common.Address]*InfoReadWrite, len(addresses)) 92 93 for addr, addrInfo := range addresses { 94 var nonce *uint64 = nil 95 var balance *big.Int = nil 96 var ok bool 97 98 address := common.HexToAddress(addr) 99 100 if addrInfo.Nonce != "" { 101 bigNonce, ok := new(big.Int).SetString(addrInfo.Nonce, encoding.Base10) 102 if !ok { 103 log.Debugf("received nonce as string: %v", addrInfo.Nonce) 104 return nil, fmt.Errorf("error while parsing address nonce") 105 } 106 nonceNp := bigNonce.Uint64() 107 nonce = &nonceNp 108 } 109 110 if addrInfo.Balance != "" { 111 balance, ok = new(big.Int).SetString(addrInfo.Balance, encoding.Base10) 112 if !ok { 113 log.Debugf("received balance as string: %v", addrInfo.Balance) 114 return nil, fmt.Errorf("error while parsing address balance") 115 } 116 } 117 118 results[address] = &InfoReadWrite{Address: address, Nonce: nonce, Balance: balance} 119 } 120 121 return results, nil 122 } 123 124 func (s *State) convertToProcessTransactionResponse(txs []types.Transaction, responses []*pb.ProcessTransactionResponse) ([]*ProcessTransactionResponse, error) { 125 results := make([]*ProcessTransactionResponse, 0, len(responses)) 126 for i, response := range responses { 127 trace, err := convertToStructLogArray(response.ExecutionTrace) 128 if err != nil { 129 return nil, err 130 } 131 132 result := new(ProcessTransactionResponse) 133 result.TxHash = common.BytesToHash(response.TxHash) 134 result.Type = response.Type 135 result.ReturnValue = response.ReturnValue 136 result.GasLeft = response.GasLeft 137 result.GasUsed = response.GasUsed 138 result.GasRefunded = response.GasRefunded 139 result.RomError = executor.RomErr(response.Error) 140 result.CreateAddress = common.HexToAddress(response.CreateAddress) 141 result.StateRoot = common.BytesToHash(response.StateRoot) 142 result.Logs = convertToLog(response.Logs) 143 result.ChangesStateRoot = IsStateRootChanged(response.Error) 144 result.ExecutionTrace = *trace 145 result.CallTrace = convertToExecutorTrace(response.CallTrace) 146 result.Tx = txs[i] 147 148 _, err = DecodeTx(common.Bytes2Hex(response.GetRlpTx())) 149 if err != nil { 150 timestamp := time.Now() 151 log.Errorf("error decoding rlp returned by executor %v at %v", err, timestamp) 152 153 event := &event.Event{ 154 ReceivedAt: timestamp, 155 Source: event.Source_Node, 156 Level: event.Level_Error, 157 EventID: event.EventID_ExecutorRLPError, 158 Json: string(response.GetRlpTx()), 159 } 160 161 err = s.eventLog.LogEvent(context.Background(), event) 162 if err != nil { 163 log.Errorf("error storing payload: %v", err) 164 } 165 } 166 167 results = append(results, result) 168 169 log.Debugf("ProcessTransactionResponse[TxHash]: %v", result.TxHash) 170 log.Debugf("ProcessTransactionResponse[Nonce]: %v", result.Tx.Nonce()) 171 log.Debugf("ProcessTransactionResponse[StateRoot]: %v", result.StateRoot.String()) 172 log.Debugf("ProcessTransactionResponse[Error]: %v", result.RomError) 173 log.Debugf("ProcessTransactionResponse[GasUsed]: %v", result.GasUsed) 174 log.Debugf("ProcessTransactionResponse[GasLeft]: %v", result.GasLeft) 175 log.Debugf("ProcessTransactionResponse[GasRefunded]: %v", result.GasRefunded) 176 log.Debugf("ProcessTransactionResponse[ChangesStateRoot]: %v", result.ChangesStateRoot) 177 } 178 179 return results, nil 180 } 181 182 func convertToLog(protoLogs []*pb.Log) []*types.Log { 183 logs := make([]*types.Log, 0, len(protoLogs)) 184 185 for _, protoLog := range protoLogs { 186 log := new(types.Log) 187 log.Address = common.HexToAddress(protoLog.Address) 188 log.Topics = convertToTopics(protoLog.Topics) 189 log.Data = protoLog.Data 190 log.BlockNumber = protoLog.BatchNumber 191 log.TxHash = common.BytesToHash(protoLog.TxHash) 192 log.TxIndex = uint(protoLog.TxIndex) 193 log.BlockHash = common.BytesToHash(protoLog.BatchHash) 194 log.Index = uint(protoLog.Index) 195 logs = append(logs, log) 196 } 197 198 return logs 199 } 200 201 func convertToTopics(responses [][]byte) []common.Hash { 202 results := make([]common.Hash, 0, len(responses)) 203 204 for _, response := range responses { 205 results = append(results, common.BytesToHash(response)) 206 } 207 return results 208 } 209 210 func convertToStructLogArray(responses []*pb.ExecutionTraceStep) (*[]instrumentation.StructLog, error) { 211 results := make([]instrumentation.StructLog, 0, len(responses)) 212 213 for _, response := range responses { 214 convertedStack, err := convertToBigIntArray(response.Stack) 215 if err != nil { 216 return nil, err 217 } 218 result := new(instrumentation.StructLog) 219 result.Pc = response.Pc 220 result.Op = response.Op 221 result.Gas = response.RemainingGas 222 result.GasCost = response.GasCost 223 result.Memory = response.Memory 224 result.MemorySize = int(response.MemorySize) 225 result.Stack = convertedStack 226 result.ReturnData = response.ReturnData 227 result.Storage = convertToProperMap(response.Storage) 228 result.Depth = int(response.Depth) 229 result.RefundCounter = response.GasRefund 230 result.Err = executor.RomErr(response.Error) 231 232 results = append(results, *result) 233 } 234 return &results, nil 235 } 236 237 func convertToBigIntArray(responses []string) ([]*big.Int, error) { 238 results := make([]*big.Int, 0, len(responses)) 239 240 for _, response := range responses { 241 result, ok := new(big.Int).SetString(response, hex.Base) 242 if ok { 243 results = append(results, result) 244 } else { 245 return nil, fmt.Errorf("string %s is not valid", response) 246 } 247 } 248 return results, nil 249 } 250 251 func convertToProperMap(responses map[string]string) map[common.Hash]common.Hash { 252 results := make(map[common.Hash]common.Hash, len(responses)) 253 for key, response := range responses { 254 results[common.HexToHash(key)] = common.HexToHash(response) 255 } 256 return results 257 } 258 259 func convertToExecutorTrace(callTrace *pb.CallTrace) instrumentation.ExecutorTrace { 260 trace := new(instrumentation.ExecutorTrace) 261 if callTrace != nil { 262 trace.Context = convertToContext(callTrace.Context) 263 trace.Steps = convertToInstrumentationSteps(callTrace.Steps) 264 } 265 266 return *trace 267 } 268 269 func convertToContext(context *pb.TransactionContext) instrumentation.Context { 270 return instrumentation.Context{ 271 Type: context.Type, 272 From: context.From, 273 To: context.To, 274 Input: string(context.Data), 275 Gas: fmt.Sprint(context.Gas), 276 Value: context.Value, 277 Output: string(context.Output), 278 GasPrice: context.GasPrice, 279 OldStateRoot: string(context.OldStateRoot), 280 Time: uint64(context.ExecutionTime), 281 GasUsed: fmt.Sprint(context.GasUsed), 282 } 283 } 284 285 func convertToInstrumentationSteps(responses []*pb.TransactionStep) []instrumentation.Step { 286 results := make([]instrumentation.Step, 0, len(responses)) 287 for _, response := range responses { 288 step := new(instrumentation.Step) 289 step.StateRoot = string(response.StateRoot) 290 step.Depth = int(response.Depth) 291 step.Pc = response.Pc 292 step.Gas = fmt.Sprint(response.Gas) 293 step.OpCode = fakevm.OpCode(response.Op).String() 294 step.Refund = fmt.Sprint(response.GasRefund) 295 step.Op = fmt.Sprint(response.Op) 296 err := executor.RomErr(response.Error) 297 if err != nil { 298 step.Error = err.Error() 299 } 300 step.Contract = convertToInstrumentationContract(response.Contract) 301 step.GasCost = fmt.Sprint(response.GasCost) 302 step.Stack = response.Stack 303 step.Memory = make([]byte, len(response.Memory)) 304 copy(step.Memory, response.Memory) 305 step.ReturnData = make([]byte, len(response.ReturnData)) 306 copy(step.ReturnData, response.ReturnData) 307 results = append(results, *step) 308 } 309 return results 310 } 311 312 func convertToInstrumentationContract(response *pb.Contract) instrumentation.Contract { 313 return instrumentation.Contract{ 314 Address: response.Address, 315 Caller: response.Caller, 316 Value: response.Value, 317 Input: string(response.Data), 318 Gas: fmt.Sprint(response.Gas), 319 } 320 } 321 322 func convertToCounters(resp *pb.ProcessBatchResponse) ZKCounters { 323 return ZKCounters{ 324 CumulativeGasUsed: resp.CumulativeGasUsed, 325 UsedKeccakHashes: resp.CntKeccakHashes, 326 UsedPoseidonHashes: resp.CntPoseidonHashes, 327 UsedPoseidonPaddings: resp.CntPoseidonPaddings, 328 UsedMemAligns: resp.CntMemAligns, 329 UsedArithmetics: resp.CntArithmetics, 330 UsedBinaries: resp.CntBinaries, 331 UsedSteps: resp.CntSteps, 332 } 333 }