diff --git a/src/config/zkresult.cpp b/src/config/zkresult.cpp index 4471d28c7..21adaf072 100644 --- a/src/config/zkresult.cpp +++ b/src/config/zkresult.cpp @@ -109,7 +109,9 @@ struct { ZKR_SM_MAIN_INVALID_WITNESS, "ZKR_SM_MAIN_INVALID_WITNESS" }, { ZKR_CBOR_INVALID_DATA, "ZKR_CBOR_INVALID_DATA" }, - { ZKR_DATA_STREAM_INVALID_DATA, "ZKR_DATA_STREAM_INVALID_DATA" } + { ZKR_DATA_STREAM_INVALID_DATA, "ZKR_DATA_STREAM_INVALID_DATA" }, + + { ZKR_SM_MAIN_INVALID_TX_STATUS_ERROR, "ZKR_SM_MAIN_INVALID_TX_STATUS_ERROR" } }; string zkresult2string (int code) diff --git a/src/config/zkresult.hpp b/src/config/zkresult.hpp index 9a62306ac..0448aa0d5 100644 --- a/src/config/zkresult.hpp +++ b/src/config/zkresult.hpp @@ -110,6 +110,8 @@ typedef enum : int ZKR_SM_MAIN_INVALID_WITNESS = 96, // Main state machine input witness is invalid or corrupt ZKR_CBOR_INVALID_DATA = 97, // CBOR data is invalid ZKR_DATA_STREAM_INVALID_DATA = 98, // Data stream data is invalid + + ZKR_SM_MAIN_INVALID_TX_STATUS_ERROR = 99, // Invalid TX status-error combination } zkresult; diff --git a/src/grpc/gen/executor.pb.cc b/src/grpc/gen/executor.pb.cc index 390bbe182..f7ad4b1d7 100644 --- a/src/grpc/gen/executor.pb.cc +++ b/src/grpc/gen/executor.pb.cc @@ -1733,7 +1733,7 @@ const char descriptor_table_protodef_executor_2eproto[] PROTOBUF_SECTION_VARIABL "IRST_TX_CHANGE_L2_BLOCK\020 \0228\n4ROM_ERROR_I" "NVALID_TX_CHANGE_L2_BLOCK_LIMIT_TIMESTAM" "P\020!\0226\n2ROM_ERROR_INVALID_TX_CHANGE_L2_BL" - "OCK_MIN_TIMESTAMP\020\"*\271+\n\rExecutorError\022\036\n" + "OCK_MIN_TIMESTAMP\020\"*\355+\n\rExecutorError\022\036\n" "\032EXECUTOR_ERROR_UNSPECIFIED\020\000\022\033\n\027EXECUTO" "R_ERROR_NO_ERROR\020\001\022\033\n\027EXECUTOR_ERROR_DB_" "ERROR\020\002\0222\n.EXECUTOR_ERROR_SM_MAIN_COUNTE" @@ -1872,19 +1872,20 @@ const char descriptor_table_protodef_executor_2eproto[] PROTOBUF_SECTION_VARIABL "ERROR_INVALID_WITNESS\020q\022\037\n\033EXECUTOR_ERRO" "R_INVALID_CBOR\020r\022&\n\"EXECUTOR_ERROR_INVAL" "ID_DATA_STREAM\020s\022-\n)EXECUTOR_ERROR_INVAL" - "ID_UPDATE_MERKLE_TREE\020t2\205\003\n\017ExecutorServ" - "ice\022U\n\014ProcessBatch\022 .executor.v1.Proces" - "sBatchRequest\032!.executor.v1.ProcessBatch" - "Response\"\000\022[\n\016ProcessBatchV2\022\".executor." - "v1.ProcessBatchRequestV2\032#.executor.v1.P" - "rocessBatchResponseV2\"\000\022m\n\027ProcessStatel" - "essBatchV2\022+.executor.v1.ProcessStateles" - "sBatchRequestV2\032#.executor.v1.ProcessBat" - "chResponseV2\"\000\022O\n\016GetFlushStatus\022\026.googl" - "e.protobuf.Empty\032#.executor.v1.GetFlushS" - "tatusResponse\"\000B>ZZ::min(), ExecutorError_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::PROTOBUF_NAMESPACE_ID::int32>::max() }; bool ExecutorError_IsValid(int value); constexpr ExecutorError ExecutorError_MIN = EXECUTOR_ERROR_UNSPECIFIED; -constexpr ExecutorError ExecutorError_MAX = EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE; +constexpr ExecutorError ExecutorError_MAX = EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR; constexpr int ExecutorError_ARRAYSIZE = ExecutorError_MAX + 1; const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* ExecutorError_descriptor(); diff --git a/src/grpc/proto/executor.proto b/src/grpc/proto/executor.proto index 628d37d54..f36bf624a 100644 --- a/src/grpc/proto/executor.proto +++ b/src/grpc/proto/executor.proto @@ -890,4 +890,6 @@ enum ExecutorError { EXECUTOR_ERROR_INVALID_DATA_STREAM = 115; // EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE indicates that the provided update merkle tree is invalid, e.g. because the executor is configured not to write to database EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE = 116; + // EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR indicates that a TX has an invalid status-error combination + EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR = 117; } \ No newline at end of file diff --git a/src/main_sm/fork_8/main/full_tracer.cpp b/src/main_sm/fork_8/main/full_tracer.cpp index 082a34948..6883c2d35 100644 --- a/src/main_sm/fork_8/main/full_tracer.cpp +++ b/src/main_sm/fork_8/main/full_tracer.cpp @@ -611,13 +611,18 @@ zkresult FullTracer::onStoreLog (Context &ctx, const RomCommand &cmd) } // Store data in the proper vector - string dataString = PrependZeros(data.get_str(16), 64); if (isTopic) { + string dataString = PrependZeros(data.get_str(16), 64); it->second.topics.push_back(dataString); } else { + // Data length is stored in C + mpz_class cScalar; + getRegFromCtx(ctx, reg_C, cScalar); + uint64_t size = zkmin(cScalar.get_ui(), 32); + string dataString = PrependZeros(data.get_str(16), size*2); it->second.data.push_back(dataString); } @@ -922,14 +927,27 @@ zkresult FullTracer::onFinishBlock (Context &ctx) } // Append to response logs, overwriting log indexes to be sequential - uint64_t logIndex = 0; + //uint64_t logIndex = 0; map::iterator auxLogsIt; for (auxLogsIt = auxLogs.begin(); auxLogsIt != auxLogs.end(); auxLogsIt++) { - auxLogsIt->second.index = logIndex; - logIndex++; + // Set log index + //auxLogsIt->second.index = logIndex; + //logIndex++; + + // Set block hash auxLogsIt->second.block_hash = currentBlock.block_hash; - currentBlock.logs.push_back(auxLogsIt->second); + + // Store block log + currentBlock.logs.emplace_back(auxLogsIt->second); + + // Store transaction log + if (auxLogsIt->second.tx_index >= currentBlock.responses.size()) + { + zklog.error("FullTracer::onFinishBlock() found log.tx_index=" + to_string(auxLogsIt->second.tx_index) + " >= currentBlock.responses.size=" + to_string(currentBlock.responses.size())); + exitProcess(); + } + currentBlock.responses[auxLogsIt->second.tx_index].logs.emplace_back(auxLogsIt->second); } // Set block hash to all txs of block @@ -1657,34 +1675,18 @@ zkresult FullTracer::onFinishTx(Context &ctx, const RomCommand &cmd) currentBlock.responses[currentBlock.responses.size() - 1].has_gasprice_opcode = hasGaspriceOpcode; currentBlock.responses[currentBlock.responses.size() - 1].has_balance_opcode = hasBalanceOpcode; - // Order all logs (from all CTX) in order of index - map auxLogs; - map>::iterator logIt; - map::const_iterator it; - for (logIt=logs.begin(); logIt!=logs.end(); logIt++) - { - for (it = logIt->second.begin(); it != logIt->second.end(); it++) - { - auxLogs[it->second.index] = it->second; - } - } + // Increase transaction index + txIndex++; - // Append to response logs, overwriting log indexes to be sequential - uint64_t logIndex = 0; - map::iterator auxLogsIt; - for (auxLogsIt = auxLogs.begin(); auxLogsIt != auxLogs.end(); auxLogsIt++) + // Check TX status + if ((response.error.empty() && (response.status == 0)) || (!response.error.empty() && (response.status == 1))) { - auxLogsIt->second.index = logIndex; - logIndex++; - currentBlock.responses[currentBlock.responses.size() - 1].logs.push_back(auxLogsIt->second); + zklog.error("FullTracer::onFinishTx() invalid TX status-error error=" + response.error + " status=" + to_string(response.status)); + return ZKR_SM_MAIN_INVALID_TX_STATUS_ERROR; } - // Increase transaction index - txIndex++; - // Clean aux array for next iteration full_trace.clear(); - logs.clear(); callData.clear(); // Reset opcodes counters @@ -2119,6 +2121,67 @@ zkresult FullTracer::onOpcode(Context &ctx, const RomCommand &cmd) uint64_t numOpcodes = full_trace.size(); Opcode * prevTraceCall = (numOpcodes > 0) ? &full_trace.at(numOpcodes - 1) : NULL; + // In case there is a log0 with 0 data length (and 0 topics), we must add it manually to logs array because it + // wont be added detected by onStoreLog event + if (codeId == 0xa0 /* LOG0 */) + { + // Get current log index + zkr = getVarFromCtx(ctx, true, ctx.rom.currentLogIndexOffset, auxScalar); + if (zkr != ZKR_SUCCESS) + { + zklog.error("FullTracer::onOpcode() failed calling getVarFromCtx(ctx.rom.currentLogIndexOffset)"); + return zkr; + } + uint64_t indexLog = auxScalar.get_ui(); + + // Init logs[CTX][indexLog], if required + uint64_t CTX = ctx.fr.toU64(ctx.pols.CTX[*ctx.pStep]); + map>::iterator itCTX; + itCTX = logs.find(CTX); + if (itCTX == logs.end()) + { + map aux; + LogV2 log; + aux[indexLog] = log; + logs[CTX] = aux; + itCTX = logs.find(CTX); + zkassert(itCTX != logs.end()); + } + + map::iterator it; + it = itCTX->second.find(indexLog); + if (it == itCTX->second.end()) + { + LogV2 log; + logs[CTX][indexLog] = log; + it = itCTX->second.find(indexLog); + zkassert(it != itCTX->second.end()); + } + + it->second.data.clear(); + + // Add log info + mpz_class auxScalar; + zkr = getVarFromCtx(ctx, false, ctx.rom.storageAddrOffset, auxScalar); + if (zkr != ZKR_SUCCESS) + { + zklog.error("FullTracer::onOpcode() failed calling getVarFromCtx(ctx.rom.storageAddrOffset)"); + return zkr; + } + it->second.address = NormalizeTo0xNFormat(auxScalar.get_str(16), 40); + zkr = getVarFromCtx(ctx, true, ctx.rom.blockNumOffset, auxScalar); + if (zkr != ZKR_SUCCESS) + { + zklog.error("FullTracer::onOpcode() failed calling getVarFromCtx(ctx.rom.blockNumOffset)"); + return zkr; + } + it->second.block_number = auxScalar.get_ui(); + it->second.tx_hash = currentBlock.responses[txIndex].tx_hash; + it->second.tx_hash_l2 = currentBlock.responses[txIndex].tx_hash_l2; + it->second.tx_index = txIndex; + it->second.index = indexLog; + } + #ifdef LOG_TIME_STATISTICS tmsop.add("getCodeName", TimeDiff(top)); #endif diff --git a/src/main_sm/fork_8/main/rom.cpp b/src/main_sm/fork_8/main/rom.cpp index 9b7b477ef..4250056b1 100644 --- a/src/main_sm/fork_8/main/rom.cpp +++ b/src/main_sm/fork_8/main/rom.cpp @@ -78,6 +78,7 @@ void Rom::load(Goldilocks &fr, json &romJson) l2TxHashOffset = getMemoryOffset("l2TxHash"); currentTxOffset = getMemoryOffset("currentTx"); txStatusOffset = getMemoryOffset("txStatus"); + currentLogIndexOffset = getMemoryOffset("currentLogIndex"); } // Load ROM integer constants diff --git a/src/main_sm/fork_8/main/rom.hpp b/src/main_sm/fork_8/main/rom.hpp index 43df42c2a..f5e9686d5 100644 --- a/src/main_sm/fork_8/main/rom.hpp +++ b/src/main_sm/fork_8/main/rom.hpp @@ -74,6 +74,7 @@ class Rom uint64_t l2TxHashOffset; uint64_t currentTxOffset; uint64_t txStatusOffset; + uint64_t currentLogIndexOffset; /* Constants */ RomConstants constants; @@ -129,7 +130,8 @@ class Rom txIndexOffset(0), l2TxHashOffset(0), currentTxOffset(0), - txStatusOffset(0) + txStatusOffset(0), + currentLogIndexOffset(0) { }; /* Destructor */ diff --git a/src/service/executor/executor_service.cpp b/src/service/executor/executor_service.cpp index 78feb13ff..e7d26da15 100644 --- a/src/service/executor/executor_service.cpp +++ b/src/service/executor/executor_service.cpp @@ -1475,6 +1475,8 @@ ::grpc::Status ExecutorServiceImpl::ProcessBatchV2 (::grpc::ServerContext* conte pTransactionContext->set_gas_used(responses[tx].full_trace.context.gas_used); // Total gas used as result of execution pTransactionContext->set_execution_time(responses[tx].full_trace.context.execution_time); pTransactionContext->set_old_state_root(string2ba(responses[tx].full_trace.context.old_state_root)); // Starting state root + pTransactionContext->set_chain_id(responses[tx].full_trace.context.chainId); + pTransactionContext->set_tx_index(responses[tx].full_trace.context.txIndex); for (uint64_t step=0; stepadd_steps(); @@ -2555,6 +2557,8 @@ ::executor::v1::ExecutorError ExecutorServiceImpl::zkresult2error (zkresult &res case ZKR_CBOR_INVALID_DATA: return ::executor::v1::EXECUTOR_ERROR_INVALID_CBOR; case ZKR_DATA_STREAM_INVALID_DATA: return ::executor::v1::EXECUTOR_ERROR_INVALID_DATA_STREAM; + case ZKR_SM_MAIN_INVALID_TX_STATUS_ERROR: return ::executor::v1::EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR; + case ZKR_AGGREGATED_PROOF_INVALID_INPUT: // Only returned when generating a proof case ZKR_DB_VERSION_NOT_FOUND_KVDB: // To be mapped to an executor error when HashDB64 is operative case ZKR_DB_VERSION_NOT_FOUND_GLOBAL: // To be mapped to an executor error when HashDB64 is operative