diff --git a/src/action/evm_bytecode_visitor.h b/src/action/evm_bytecode_visitor.h index d1892a4f5..2fae8b737 100644 --- a/src/action/evm_bytecode_visitor.h +++ b/src/action/evm_bytecode_visitor.h @@ -124,6 +124,47 @@ template class EVMByteCodeVisitor { } } + template + struct HasSetCompatibleDynamicJumpTargets : std::false_type {}; + template + struct HasSetCompatibleDynamicJumpTargets< + T, + std::void_t().setCompatibleDynamicJumpTargets( + uint64_t{}, std::declval &>()))>> + : std::true_type {}; + + void initializeCompatibleDynamicJumpTargets(const EVMAnalyzer &Analyzer) { + if constexpr (HasSetCompatibleDynamicJumpTargets::value) { + for (const auto &[EntryPC, BlockInfo] : Analyzer.getBlockInfos()) { + (void)BlockInfo; + const std::vector TargetBlockPCs = + Analyzer.getPotentialDynamicJumpTargetBlocksForSourceBlock(EntryPC); + if (TargetBlockPCs.empty()) { + continue; + } + Builder.setCompatibleDynamicJumpTargets(EntryPC, TargetBlockPCs); + } + } else { + (void)Analyzer; + } + } + + template + struct HasRegisterDirectLiftedPhiIncoming : std::false_type {}; + template + struct HasRegisterDirectLiftedPhiIncoming< + T, + std::void_t().registerDirectLiftedPhiIncoming( + uint64_t{}, uint64_t{}))>> : std::true_type {}; + + void registerDirectLiftedPhiIncoming(uint64_t BlockPC) { + if constexpr (HasRegisterDirectLiftedPhiIncoming::value) { + Builder.registerDirectLiftedPhiIncoming(BlockPC, CurrentBlockEntryPC); + } else { + (void)BlockPC; + } + } + void push(const Operand &Opnd) { Stack.push(Opnd); } void requireLogicalStackDepth(uint32_t Depth) { @@ -193,7 +234,9 @@ template class EVMByteCodeVisitor { PC++; continue; } - Builder.meterOpcode(Opcode, PC); + if (Opcode != OP_BLOCKHASH) { + Builder.meterOpcode(Opcode, PC); + } } switch (Opcode) { @@ -693,7 +736,7 @@ template class EVMByteCodeVisitor { HasKnownSucc && isLiftedBlock(SuccPC); auto OutgoingStack = drainLogicalStack(); if (HasKnownLiftedSucc) { - assignLiftedEntryState(SuccPC, OutgoingStack); + assignDirectLiftedEntryState(SuccPC, OutgoingStack); } if (!HasKnownSucc) { assignCompatibleDynamicJumpRegionEntryStates(Analyzer, @@ -749,17 +792,17 @@ template class EVMByteCodeVisitor { if (CanTransferWithoutMaterialize) { auto OutgoingStack = drainLogicalStack(); - assignLiftedEntryState(FallthroughPC, OutgoingStack); - assignLiftedEntryState(JumpSuccPC, OutgoingStack); + assignDirectLiftedEntryState(FallthroughPC, OutgoingStack); + assignDirectLiftedEntryState(JumpSuccPC, OutgoingStack); finalizeBlockExit(std::move(OutgoingStack), false); } else { if (CurrentBlockLifted) { auto OutgoingStack = drainLogicalStack(); if (CanPreassignFallthrough) { - assignLiftedEntryState(FallthroughPC, OutgoingStack); + assignDirectLiftedEntryState(FallthroughPC, OutgoingStack); } if (CanPreassignJump) { - assignLiftedEntryState(JumpSuccPC, OutgoingStack); + assignDirectLiftedEntryState(JumpSuccPC, OutgoingStack); } if (!HasJumpSucc) { assignCompatibleDynamicJumpRegionEntryStates(Analyzer, @@ -807,12 +850,19 @@ template class EVMByteCodeVisitor { if (PC > RunStartPC && HasLiveFallthrough) { Builder.meterOpcodeRange(RunStartPC, PC); } + if (HasLiveFallthrough && PC == CurrentBlockEntryPC) { + if (!CurrentBlockNeedsFinalize) { + Builder.meterOpcode(Opcode, PC); + } + registerCurrentBlockPC(PC); + break; + } if (HasLiveFallthrough && tryAssignFallthroughEntryState(PC)) { // Keep runtime stack materialization elided on lifted fallthrough. } else { if (HasLiveFallthrough && CurrentBlockLifted && isLiftedBlock(PC)) { auto OutgoingStack = drainLogicalStack(); - assignLiftedEntryState(PC, OutgoingStack); + assignDirectLiftedEntryState(PC, OutgoingStack); finalizeBlockExit(std::move(OutgoingStack), false); } else { handleEndBlock(); @@ -822,8 +872,7 @@ template class EVMByteCodeVisitor { } } Builder.handleJumpDest(PC); - handleBeginBlock(Analyzer); - Builder.meterOpcode(Opcode, PC); + handleBeginBlock(Analyzer, true); break; } @@ -882,6 +931,7 @@ template class EVMByteCodeVisitor { } void initializeLiftedBlocks(const EVMAnalyzer &Analyzer) { + initializeCompatibleDynamicJumpTargets(Analyzer); StackLifter.initialize(Analyzer); } @@ -928,21 +978,55 @@ template class EVMByteCodeVisitor { } void finalizeBlockExit(std::vector Values, bool Materialize) { + if (!CurrentBlockNeedsFinalize) { + return; + } + if (CurrentBlockEntryPC == 2289 || CurrentBlockEntryPC == 2293 || + CurrentBlockEntryPC == 2304 || CurrentBlockEntryPC == 2319 || + CurrentBlockEntryPC == 2356) { + fprintf(stderr, + "[block-exit-debug] pc=%lu lifted=%d materialize=%d values=%zu " + "hidden_prefix=%u\n", + (unsigned long)CurrentBlockEntryPC, CurrentBlockLifted, + Materialize, Values.size(), CurrentBlockHiddenLiveInPrefixDepth); + } Builder.endMemoryCompileBlock(); CurBlockLinearPrecheckPlan = BlockLinearPrecheckPlan(); if (Materialize) { if (CurrentBlockLifted) { - spillTrackedStackPreservingPrefix(Values, - CurrentBlockHiddenLiveInPrefixDepth); + if (CurrentBlockHiddenLiveInPrefixDepth > 0) { + const size_t HiddenPrefixDepth = + static_cast(CurrentBlockHiddenLiveInPrefixDepth); + ZEN_ASSERT(HiddenPrefixDepth <= Values.size() && + "Hidden live-in prefix must fit within the logical stack"); + std::vector VisibleSuffix( + Values.begin() + static_cast(HiddenPrefixDepth), + Values.end()); + spillTrackedStackPreservingPrefix( + VisibleSuffix, CurrentBlockHiddenLiveInPrefixDepth); + } else { + spillTrackedStackPreservingPrefix(Values, 0); + } } else { for (const Operand &Opnd : Values) { Builder.stackPush(Opnd); } + Builder.syncTrackedStackMetadataToInstance(); } } InDeadCode = true; CurrentBlockLifted = false; CurrentBlockHiddenLiveInPrefixDepth = 0; + CurrentBlockNeedsFinalize = false; + } + + void abandonCurrentBlockAfterTrap() { + Builder.endMemoryCompileBlock(); + CurBlockLinearPrecheckPlan = BlockLinearPrecheckPlan(); + InDeadCode = true; + CurrentBlockLifted = false; + CurrentBlockHiddenLiveInPrefixDepth = 0; + CurrentBlockNeedsFinalize = false; } bool tryGetConstantJumpSuccessorPC(const EVMAnalyzer &Analyzer, @@ -968,6 +1052,12 @@ template class EVMByteCodeVisitor { StackLifter.assignEntryState(CurrentBlockEntryPC, BlockPC, Values); } + void assignDirectLiftedEntryState(uint64_t BlockPC, + const std::vector &Values) { + registerDirectLiftedPhiIncoming(BlockPC); + assignLiftedEntryState(BlockPC, Values); + } + void assignCompatibleDynamicJumpRegionEntryStates( const EVMAnalyzer &Analyzer, const std::vector &Values) { for (uint64_t TargetBlockPC : @@ -1001,6 +1091,7 @@ template class EVMByteCodeVisitor { BlockPC)) { return; } + registerDirectLiftedPhiIncoming(BlockPC); StackLifter.assignEntryState( CurrentBlockEntryPC, BlockPC, loadLiftedEntryStateFromRuntime(Analyzer, BlockPC)); @@ -1015,7 +1106,7 @@ template class EVMByteCodeVisitor { return false; } auto OutgoingStack = drainLogicalStack(); - assignLiftedEntryState(SuccPC, OutgoingStack); + assignDirectLiftedEntryState(SuccPC, OutgoingStack); finalizeBlockExit(std::move(OutgoingStack), false); return true; } @@ -1025,7 +1116,7 @@ template class EVMByteCodeVisitor { return false; } auto OutgoingStack = drainLogicalStack(); - assignLiftedEntryState(SuccPC, OutgoingStack); + assignDirectLiftedEntryState(SuccPC, OutgoingStack); finalizeBlockExit(std::move(OutgoingStack), false); return true; } @@ -1062,8 +1153,7 @@ template class EVMByteCodeVisitor { EntryDepth + static_cast(BlockInfo.MinStackHeight); if (MinDepth < 0) { Builder.handleTrap(common::ErrorCode::EVMStackUnderflow); - InDeadCode = true; - CurrentBlockLifted = false; + abandonCurrentBlockAfterTrap(); return false; } @@ -1071,18 +1161,23 @@ template class EVMByteCodeVisitor { EntryDepth + static_cast(BlockInfo.MaxStackHeight); if (MaxDepth > static_cast(EVM_MAX_STACK_SIZE)) { Builder.handleTrap(common::ErrorCode::EVMStackOverflow); - InDeadCode = true; - CurrentBlockLifted = false; + abandonCurrentBlockAfterTrap(); return false; } return true; } - void handleBeginBlock(EVMAnalyzer &Analyzer) { + void handleBeginBlock(EVMAnalyzer &Analyzer, + bool EntryAlreadyRouted = false) { const auto &BlockInfos = Analyzer.getBlockInfos(); ZEN_ASSERT(BlockInfos.count(PC) > 0 && "Block info not found"); + const auto &BlockInfo = BlockInfos.at(PC); + if (!EntryAlreadyRouted && BlockInfo.IsJumpDest) { + Builder.handleJumpDest(PC); + } Builder.beginMemoryCompileBlock(PC); + CurrentBlockNeedsFinalize = true; CurBlockLinearPrecheckPlan = BlockLinearPrecheckPlan(); const Byte *Bytecode = Ctx->getBytecode(); size_t BytecodeSize = Ctx->getBytecodeSize(); @@ -1101,7 +1196,6 @@ template class EVMByteCodeVisitor { CurBlockLinearPrecheckPlan.CoveredOpcode == OP_MSTORE); } } - const auto &BlockInfo = BlockInfos.at(PC); CurrentBlockEntryPC = PC; CurrentBlockHiddenLiveInPrefixDepth = 0; registerCurrentBlockPC(PC); @@ -1112,18 +1206,17 @@ template class EVMByteCodeVisitor { if (static_cast(-BlockInfo.MinStackHeight) > EVM_MAX_STACK_SIZE) { Builder.handleTrap(common::ErrorCode::EVMStackUnderflow); - InDeadCode = true; - CurrentBlockLifted = false; + abandonCurrentBlockAfterTrap(); return; } if (static_cast(BlockInfo.MaxStackHeight) > EVM_MAX_STACK_SIZE) { Builder.handleTrap(common::ErrorCode::EVMStackOverflow); - InDeadCode = true; - CurrentBlockLifted = false; + abandonCurrentBlockAfterTrap(); return; } InDeadCode = false; if (!LiftedBlock) { + Builder.reloadTrackedStackFromInstance(); Builder.createStackCheckBlock(-BlockInfo.MinStackHeight, 1024 - BlockInfo.MaxStackHeight); } @@ -1139,6 +1232,10 @@ template class EVMByteCodeVisitor { CurrentBlockLifted = false; int32_t TotalPopSize = -BlockInfo.MinPopHeight; + if (BlockInfo.HiddenLiveInPrefixDepth > 0 && + BlockInfo.FullEntryStateDepth > TotalPopSize) { + TotalPopSize = BlockInfo.FullEntryStateDepth; + } EvalStack ReverseStack; // Refine each popped Operand's ValueRange from analyzer-computed entry // ranges so u64-narrow fast paths fire on values flowing through CFG @@ -1151,9 +1248,17 @@ template class EVMByteCodeVisitor { while (TotalPopSize > 0) { Operand Opnd = Builder.stackPop(); const int32_t SlotIdx = EntryTopIdx - PopIter; + EVMValueRange SlotRange = EVMValueRange::U256; if (SlotIdx >= 0 && SlotIdx < static_cast(EntryRanges.size())) { - Opnd.setRange(EntryRanges[SlotIdx]); + SlotRange = EntryRanges[SlotIdx]; + Opnd.setRange(SlotRange); } + // Anchor runtime-preloaded entry values in dedicated vars so later deep + // stack uses do not depend on reusing raw load trees across + // pops/branches. + Operand AnchoredOpnd = Builder.createStackEntryOperand(SlotRange); + Builder.assignStackEntryOperand(AnchoredOpnd, Opnd); + Opnd = AnchoredOpnd; ReverseStack.push(Opnd); ++PopIter; --TotalPopSize; @@ -1192,7 +1297,12 @@ template class EVMByteCodeVisitor { } } - void handleEndBlock() { finalizeBlockExit(drainLogicalStack(), true); } + void handleEndBlock() { + if (!CurrentBlockNeedsFinalize) { + return; + } + finalizeBlockExit(drainLogicalStack(), true); + } void handleStop() { Builder.handleStop(); } @@ -1920,6 +2030,7 @@ template class EVMByteCodeVisitor { uint64_t CurrentBlockEntryPC = 0; bool CurrentBlockLifted = false; uint32_t CurrentBlockHiddenLiveInPrefixDepth = 0; + bool CurrentBlockNeedsFinalize = false; }; } // namespace COMPILER diff --git a/src/compiler/evm_compiler.cpp b/src/compiler/evm_compiler.cpp index 28ee695e5..f0d6de97a 100644 --- a/src/compiler/evm_compiler.cpp +++ b/src/compiler/evm_compiler.cpp @@ -99,7 +99,6 @@ void EagerEVMJITCompiler::compile() { ZEN_ASSERT(Ctx.ExternRelocs.empty()); uint8_t *JITFuncPtr = Ctx.CodePtr + Ctx.FuncOffsetMap[0]; - EVMMod->setJITCodeAndSize(JITFuncPtr, Ctx.CodeSize); #ifdef ZEN_ENABLE_LINUX_PERF // Write block symbols instead of EVM_Main // JIT_DUMP_WRITE_FUNC("EVM_Main", JITFuncPtr, Ctx.FuncSizeMap[0]); @@ -114,7 +113,11 @@ void EagerEVMJITCompiler::compile() { size_t CodeSize = CodeMPool.getMemEnd() - JITCode; platform::mprotect(JITCode, TO_MPROTECT_CODE_SIZE(CodeSize), PROT_READ | PROT_EXEC); - EVMMod->setJITCodeAndSize(JITCode, CodeSize); + // Runtime must enter at the compiled EVM main function, not at the start of + // the backing code buffer. In release builds the first function may have a + // non-zero offset due to emitted helper blocks, and using the raw buffer + // base as the entrypoint jumps into unrelated code. + EVMMod->setJITCodeAndSize(JITFuncPtr, CodeSize - Ctx.FuncOffsetMap[0]); Stats.stopRecord(Timer); } diff --git a/src/compiler/evm_frontend/evm_analyzer.h b/src/compiler/evm_frontend/evm_analyzer.h index 70d441f05..2f4d8e1ca 100644 --- a/src/compiler/evm_frontend/evm_analyzer.h +++ b/src/compiler/evm_frontend/evm_analyzer.h @@ -319,6 +319,44 @@ class EVMAnalyzer { return collectDynamicJumpSourceBlocksForInfo(It->second); } + std::vector + getPotentialDynamicJumpTargetBlocksForSourceBlock(uint64_t BlockPC) const { + auto It = BlockInfos.find(BlockPC); + if (It == BlockInfos.end()) { + return {}; + } + if (!It->second.HasDynamicJump) { + return {}; + } + if (It->second.DynamicJumpTargetRegionEntryPC != 0) { + std::vector TargetBlockPCs; + for (const auto &[EntryPC, Info] : BlockInfos) { + if (hasDynamicJumpRegion(Info, + It->second.DynamicJumpTargetRegionEntryPC)) { + appendUniqueBlockPC(TargetBlockPCs, EntryPC); + } + } + if (!TargetBlockPCs.empty()) { + return TargetBlockPCs; + } + } + std::vector CompatibleTargetBlockPCs = + getCompatibleDynamicJumpTargetBlocksForSourceBlock(BlockPC); + if (!CompatibleTargetBlockPCs.empty()) { + return CompatibleTargetBlockPCs; + } + if (HasUnknownDynamicJump) { + std::vector TargetBlockPCs; + for (const auto &[EntryPC, Info] : BlockInfos) { + if (Info.IsDynamicJumpTargetCandidate) { + appendUniqueBlockPC(TargetBlockPCs, EntryPC); + } + } + return TargetBlockPCs; + } + return {}; + } + std::vector getPotentialEntryPredecessorsForBlock(uint64_t BlockPC) const { auto It = BlockInfos.find(BlockPC); @@ -328,9 +366,41 @@ class EVMAnalyzer { std::vector PredBlockPCs(It->second.Predecessors.begin(), It->second.Predecessors.end()); - for (uint64_t PredBlockPC : - collectDynamicJumpSourceBlocksForInfo(It->second)) { - appendUniqueBlockPC(PredBlockPCs, PredBlockPC); + if (std::find(It->second.Successors.begin(), It->second.Successors.end(), + BlockPC) != It->second.Successors.end()) { + appendUniqueBlockPC(PredBlockPCs, BlockPC); + } + for (const auto &[PredBlockPC, PredInfo] : BlockInfos) { + if (!PredInfo.HasDynamicJump || PredInfo.ResolvedEntryStackDepth < 0) { + continue; + } + bool CanReachBlock = false; + if (It->second.CanLiftStack && It->second.FullEntryStateDepth >= 0 && + PredInfo.ResolvedExitStackDepth >= 0 && + PredInfo.ResolvedExitStackDepth == It->second.FullEntryStateDepth) { + CanReachBlock = true; + } + const std::vector PotentialTargetBlockPCs = + getPotentialDynamicJumpTargetBlocksForSourceBlock(PredBlockPC); + if (std::find(PotentialTargetBlockPCs.begin(), + PotentialTargetBlockPCs.end(), + BlockPC) != PotentialTargetBlockPCs.end()) { + CanReachBlock = true; + } else if (PredInfo.DynamicJumpTargetRegionEntryPC != 0) { + const auto *RegionInfo = + getDynamicJumpRegionInfo(PredInfo.DynamicJumpTargetRegionEntryPC); + if (RegionInfo && std::find(RegionInfo->TargetBlocks.begin(), + RegionInfo->TargetBlocks.end(), BlockPC) != + RegionInfo->TargetBlocks.end()) { + CanReachBlock = true; + } + } else if (HasUnknownDynamicJump && + It->second.IsDynamicJumpTargetCandidate) { + CanReachBlock = true; + } + if (CanReachBlock) { + appendUniqueBlockPC(PredBlockPCs, PredBlockPC); + } } return PredBlockPCs; } @@ -642,7 +712,8 @@ class EVMAnalyzer { break; } - bool IsUndefined = (InstructionNames[Opcode] == nullptr); + bool IsUndefined = (InstructionNames[Opcode] == nullptr) || + (InstructionMetrics[Opcode].gas_cost < 0); if (IsUndefined) { Info.HasUndefinedInstr = true; #ifdef ZEN_ENABLE_JIT_FALLBACK_TEST @@ -1217,6 +1288,27 @@ class EVMAnalyzer { return false; } + bool hasUnresolvedDynamicJumpSource(uint64_t TargetBlockPC) const { + auto It = BlockInfos.find(TargetBlockPC); + if (It == BlockInfos.end() || !It->second.IsDynamicJumpTargetCandidate) { + return false; + } + + for (const auto &[EntryPC, Info] : BlockInfos) { + if (!Info.HasDynamicJump || (Info.ResolvedEntryStackDepth >= 0 && + Info.ResolvedExitStackDepth >= 0)) { + continue; + } + const std::vector PotentialTargets = + getPotentialDynamicJumpTargetBlocksForSourceBlock(EntryPC); + if (std::find(PotentialTargets.begin(), PotentialTargets.end(), + TargetBlockPC) != PotentialTargets.end()) { + return true; + } + } + return false; + } + void finalizeLiftability() { for (auto &[EntryPC, Info] : BlockInfos) { (void)EntryPC; @@ -1224,9 +1316,13 @@ class EVMAnalyzer { bool DynamicJumpDestConflict = HasUnknownDynamicJump && Info.IsDynamicJumpTargetCandidate && !Info.HasCompatibleDynamicJumpTargetShape; + bool UnresolvedDynamicJumpSourceConflict = + HasUnknownDynamicJump && Info.IsDynamicJumpTargetCandidate && + hasUnresolvedDynamicJumpSource(EntryPC); Info.CanLiftStack = EntryKnown && !Info.HasUndefinedInstr && !Info.HasInconsistentEntryDepth && - !DynamicJumpDestConflict; + !DynamicJumpDestConflict && + !UnresolvedDynamicJumpSourceConflict; if (Info.CanLiftStack && Info.IsDynamicJumpTargetCandidate && Info.HasDeferredEntryMerge && Info.HiddenLiveInPrefixDepth > 0 && getDynamicJumpSourceBlocksForBlock(EntryPC).empty()) { @@ -1445,7 +1541,8 @@ class EVMAnalyzer { // Undefined opcodes terminate range analysis for this block; the // analyzer already marked HasUndefinedInstr and stopped scanning here. - if (InstructionNames[Opcode] == nullptr) { + if (InstructionNames[Opcode] == nullptr || + InstructionMetrics[Opcode].gas_cost < 0) { return; } diff --git a/src/compiler/evm_frontend/evm_lifted_stack_lifter.h b/src/compiler/evm_frontend/evm_lifted_stack_lifter.h index d6db0fee1..fc72e0ece 100644 --- a/src/compiler/evm_frontend/evm_lifted_stack_lifter.h +++ b/src/compiler/evm_frontend/evm_lifted_stack_lifter.h @@ -295,6 +295,13 @@ template class EVMLiftedStackLifter { } if (Index < EntryState.MergeOperands.size()) { if (!EntryState.MergeOperands[Index].isEmpty()) { + const bool HasExpectedPred = + std::find(EntryState.PredecessorOrder.begin(), + EntryState.PredecessorOrder.end(), + PredBlockPC) != EntryState.PredecessorOrder.end(); + if (!HasExpectedPred) { + continue; + } assignStackMergeOperandCompat( EntryState.MergeOperands[Index], PredBlockPC, EntryState.PendingPhis[Index].IncomingPhiValues[PredBlockPC]); diff --git a/src/compiler/evm_frontend/evm_mir_compiler.cpp b/src/compiler/evm_frontend/evm_mir_compiler.cpp index 2fdca8295..458ce1ac5 100644 --- a/src/compiler/evm_frontend/evm_mir_compiler.cpp +++ b/src/compiler/evm_frontend/evm_mir_compiler.cpp @@ -99,6 +99,17 @@ bool EVMMirBuilder::compile(CompilerContext *Context) { return Visitor.compile(); } +void EVMMirBuilder::setCompatibleDynamicJumpTargets( + uint64_t SourceBlockPC, const std::vector &TargetBlockPCs) { + CompatibleDynamicJumpTargetsBySource[SourceBlockPC] = TargetBlockPCs; +} + +void EVMMirBuilder::registerDirectLiftedPhiIncoming(uint64_t TargetBlockPC, + uint64_t PredBlockPC) { + const uint64_t CanonicalTargetPC = getCanonicalJumpDestPC(TargetBlockPC); + DynamicPhiIncomingBlockTable[CanonicalTargetPC][PredBlockPC] = CurBB; +} + void EVMMirBuilder::registerDynamicJumpPhiIncomingBlock(uint64_t TargetBlockPC, uint64_t PredBlockPC, MBasicBlock *PredBB) { @@ -109,19 +120,21 @@ void EVMMirBuilder::registerPhiIncomingBlock(uint64_t TargetBlockPC, uint64_t PredBlockPC, MBasicBlock *PredBB) { const uint64_t CanonicalTargetPC = getCanonicalJumpDestPC(TargetBlockPC); - DynamicPhiIncomingBlockTable[CanonicalTargetPC][PredBlockPC] = + MBasicBlock *ResolvedBB = resolvePhiIncomingPredecessorBB(TargetBlockPC, PredBB); + DynamicPhiIncomingBlockTable[CanonicalTargetPC][PredBlockPC] = ResolvedBB; } MBasicBlock *EVMMirBuilder::getPhiIncomingBlock(uint64_t TargetBlockPC, uint64_t PredBlockPC) const { - auto DynamicTargetIt = - DynamicPhiIncomingBlockTable.find(getCanonicalJumpDestPC(TargetBlockPC)); + const uint64_t CanonicalTargetPC = getCanonicalJumpDestPC(TargetBlockPC); + auto DynamicTargetIt = DynamicPhiIncomingBlockTable.find(CanonicalTargetPC); if (DynamicTargetIt != DynamicPhiIncomingBlockTable.end()) { auto DynamicPredIt = DynamicTargetIt->second.find(PredBlockPC); if (DynamicPredIt != DynamicTargetIt->second.end()) { - return resolveReachablePhiIncomingPredecessorBB(TargetBlockPC, - DynamicPredIt->second); + MBasicBlock *Resolved = resolveReachablePhiIncomingPredecessorBB( + TargetBlockPC, DynamicPredIt->second); + return Resolved; } } @@ -129,8 +142,9 @@ MBasicBlock *EVMMirBuilder::getPhiIncomingBlock(uint64_t TargetBlockPC, if (BlockIt == BlockEntryTable.end()) { return nullptr; } - return resolveReachablePhiIncomingPredecessorBB(TargetBlockPC, - BlockIt->second); + MBasicBlock *Resolved = + resolveReachablePhiIncomingPredecessorBB(TargetBlockPC, BlockIt->second); + return Resolved; } uint64_t EVMMirBuilder::getCanonicalJumpDestPC(uint64_t TargetBlockPC) const { @@ -260,13 +274,69 @@ MBasicBlock *EVMMirBuilder::getOrCreateIndirectJumpBB(uint64_t SourceBlockPC) { MBasicBlock *FailureBB = getOrCreateExceptionSetBB(ErrorCode::EVMBadJumpDestination); + MBasicBlock *DebugFailureBB = CurFunc->createBasicBlock(); MInstruction *JumpTarget = loadVariable(JumpTargetVar); MType *UInt64Type = EVMFrontendContext::getMIRTypeFromEVMType(EVMType::UINT64); + auto AllowedTargetsIt = + CompatibleDynamicJumpTargetsBySource.find(SourceBlockPC); + const bool HasTargetFilter = false; + if (SourceBlockPC == 2356) { + fprintf(stderr, + "[jump-lowering-debug] source=%lu jumpdests=%zu has1145=%d " + "allowed_targets=", + (unsigned long)SourceBlockPC, JumpDestTable.size(), + JumpDestTable.count(1145) != 0); + if (AllowedTargetsIt != CompatibleDynamicJumpTargetsBySource.end()) { + for (uint64_t TargetPC : AllowedTargetsIt->second) { + fprintf(stderr, "%lu,", (unsigned long)TargetPC); + } + } + fprintf(stderr, "\n"); + } + + if (HasTargetFilter) { + const std::vector &AllowedTargets = AllowedTargetsIt->second; + CompileVector> Cases( + AllowedTargets.size(), Ctx.MemPool); + for (size_t Index = 0; Index < AllowedTargets.size(); ++Index) { + const uint64_t DestPC = AllowedTargets[Index]; + auto DestIt = JumpDestTable.find(DestPC); + if (DestIt == JumpDestTable.end()) { + continue; + } + Cases[Index].first = createIntConstInstruction(UInt64Type, DestPC); + Cases[Index].second = DestIt->second; + registerDynamicJumpPhiIncomingBlock(DestPC, SourceBlockPC, + IndirectJumpBB); + addSuccessor(DestIt->second); + } + + createInstruction(true, Ctx, JumpTarget, DebugFailureBB, + Cases); + addSuccessor(DebugFailureBB); + setInsertBlock(FromBB); + return IndirectJumpBB; + } // If hash table is used, create mir to calculate hash index of JumpTarget // PC and create switch instruction with hash index if (!JumpHashTable.empty()) { + if (SourceBlockPC == 2356) { + const uint64_t TargetHash = (1145 * HashMultiplier) & HashMask; + fprintf(stderr, + "[jump-lowering-debug] source=%lu hashmask=%lu " + "target1145hash=%lu bucket=", + (unsigned long)SourceBlockPC, (unsigned long)HashMask, + (unsigned long)TargetHash); + auto BucketIt = JumpHashReverse.find(TargetHash); + if (BucketIt != JumpHashReverse.end()) { + for (uint64_t PC : BucketIt->second) { + fprintf(stderr, "%lu,", (unsigned long)PC); + } + } + fprintf(stderr, "\n"); + } // Initialize hash cases uint64_t MinHash = JumpHashTable.begin()->first; uint64_t MaxHash = JumpHashTable.rbegin()->first; @@ -290,8 +360,8 @@ MBasicBlock *EVMMirBuilder::getOrCreateIndirectJumpBB(uint64_t SourceBlockPC) { createIntConstInstruction(UInt64Type, HashEntry); if (JumpHashTable.count(HashEntry) == 0) { // FailureBB for empty hash index - HashCases[HIndex].second = FailureBB; - addUniqueSuccessor(FailureBB); + HashCases[HIndex].second = DebugFailureBB; + addSuccessor(DebugFailureBB); continue; } if (JumpHashTable[HashEntry].size() == 1) { @@ -312,9 +382,9 @@ MBasicBlock *EVMMirBuilder::getOrCreateIndirectJumpBB(uint64_t SourceBlockPC) { registerDynamicJumpPhiIncomingBlock(JumpHashReverse[HashEntry][0], SourceBlockPC, CheckBB); createInstruction(true, Ctx, IsMatch, DestBB, - FailureBB); + DebugFailureBB); addSuccessor(DestBB); - addUniqueSuccessor(FailureBB); + addSuccessor(DebugFailureBB); setInsertBlock(OutsideBB); HashCases[HIndex].second = CheckBB; addSuccessor(CheckBB); @@ -337,17 +407,21 @@ MBasicBlock *EVMMirBuilder::getOrCreateIndirectJumpBB(uint64_t SourceBlockPC) { SubCaseBB); addSuccessor(SubDestBBVec[I]); } - createInstruction(true, Ctx, JumpTarget, FailureBB, - SubCases); - addUniqueSuccessor(FailureBB); + createInstruction(true, Ctx, JumpTarget, + DebugFailureBB, SubCases); + addSuccessor(DebugFailureBB); // Back to outside BB setInsertBlock(OutsideBB); HashCases[HIndex].second = SubCaseBB; addSuccessor(SubCaseBB); } } - createInstruction(true, Ctx, HashDest, FailureBB, + createInstruction(true, Ctx, HashDest, DebugFailureBB, HashCases); + addSuccessor(DebugFailureBB); + setInsertBlock(FromBB); + setInsertBlock(DebugFailureBB); + createInstruction(true, Ctx, FailureBB); addUniqueSuccessor(FailureBB); setInsertBlock(FromBB); return IndirectJumpBB; @@ -365,7 +439,11 @@ MBasicBlock *EVMMirBuilder::getOrCreateIndirectJumpBB(uint64_t SourceBlockPC) { Index++; } - createInstruction(true, Ctx, JumpTarget, FailureBB, Cases); + createInstruction(true, Ctx, JumpTarget, DebugFailureBB, + Cases); + addSuccessor(DebugFailureBB); + setInsertBlock(DebugFailureBB); + createInstruction(true, Ctx, FailureBB); addUniqueSuccessor(FailureBB); setInsertBlock(FromBB); return IndirectJumpBB; @@ -532,15 +610,16 @@ void EVMMirBuilder::meterOpcode(evmc_opcode Opcode, uint64_t PC) { // Prefer SPP-shifted cost when available — it preserves per-path totals // while reducing the number of non-zero entries the JIT must emit a // gas check for. - const uint64_t Cost = - GasChunkCostSPP ? GasChunkCostSPP[PC] : GasChunkCost[PC]; + const uint64_t Cost = GasChunkCost[PC]; meterGas(Cost); } return; } const uint8_t Index = static_cast(Opcode); const auto &Metrics = InstructionMetrics[Index]; - meterGas(static_cast(Metrics.gas_cost)); + if (Metrics.gas_cost > 0) { + meterGas(static_cast(Metrics.gas_cost)); + } } void EVMMirBuilder::meterOpcodeRange(uint64_t StartPC, @@ -577,10 +656,11 @@ void EVMMirBuilder::meterOpcodeRange(uint64_t StartPC, uint64_t Cost = 0; if (GasChunkEnd && GasChunkCost && PC < GasChunkSize && GasChunkEnd[PC] > PC) { - Cost = GasChunkCostSPP ? GasChunkCostSPP[PC] : GasChunkCost[PC]; + Cost = GasChunkCost[PC]; } else { const uint8_t Opcode = static_cast(Bytecode[PC]); - Cost = static_cast(InstructionMetrics[Opcode].gas_cost); + const int16_t OpcodeCost = InstructionMetrics[Opcode].gas_cost; + Cost = OpcodeCost > 0 ? static_cast(OpcodeCost) : 0; } if (UINT64_MAX - TotalCost < Cost) { @@ -595,6 +675,9 @@ void EVMMirBuilder::meterOpcodeRange(uint64_t StartPC, bool EVMMirBuilder::isOpcodeDefined(evmc_opcode Opcode) const { const uint8_t Index = static_cast(Opcode); + if (InstructionMetrics && InstructionMetrics[Index].gas_cost < 0) { + return false; + } if (InstructionNames && InstructionNames[Index] != nullptr) { return true; } @@ -996,6 +1079,30 @@ typename EVMMirBuilder::Operand EVMMirBuilder::stackGet(int32_t IndexFromTop) { return Operand(GetComponents, EVMType::UINT256); } +void EVMMirBuilder::reloadTrackedStackFromInstance() { + const int32_t StackSizeOffset = + zen::runtime::EVMInstance::getEVMStackSizeOffset(); + MInstruction *StackSize = getInstanceElement(&Ctx.I64Type, StackSizeOffset); + createInstruction(true, &(Ctx.VoidType), StackSize, + StackSizeVar->getVarIdx()); + + MInstruction *StackPtrOffset = createIntConstInstruction( + &Ctx.I64Type, zen::runtime::EVMInstance::getEVMStackOffset()); + MInstruction *StackBaseAddr = createInstruction( + false, OP_add, &Ctx.I64Type, InstanceAddr, StackPtrOffset); + MInstruction *StackTopAddr = createInstruction( + false, OP_add, &Ctx.I64Type, StackBaseAddr, StackSize); + createInstruction(true, &(Ctx.VoidType), StackTopAddr, + StackTopVar->getVarIdx()); +} + +void EVMMirBuilder::syncTrackedStackMetadataToInstance() { + const int32_t StackSizeOffset = + zen::runtime::EVMInstance::getEVMStackSizeOffset(); + MInstruction *StackSize = loadVariable(StackSizeVar); + setInstanceElement(&Ctx.I64Type, StackSize, StackSizeOffset); +} + void EVMMirBuilder::setTrackedStackDepth(uint32_t Depth) { MType *I64Type = EVMFrontendContext::getMIRTypeFromEVMType(EVMType::UINT64); uint64_t StackBytes = static_cast(Depth) * 32ULL; @@ -1061,17 +1168,16 @@ typename EVMMirBuilder::Operand EVMMirBuilder::materializeStackMergeOperand( U256Inst PhiComponents = {}; U256Var PhiVars = {}; - auto PredRange = CurBB->predecessors(); - const size_t ActualPredCount = - static_cast(std::distance(PredRange.begin(), PredRange.end())); + const size_t PhiIncomingCount = PredBlockPCs.size(); for (size_t ComponentIndex = 0; ComponentIndex < EVM_ELEMENTS_COUNT; ++ComponentIndex) { - PhiInstruction *Phi = createPendingPhi(&Ctx.I64Type, PredBlockPCs.size()); + PhiInstruction *Phi = createPendingPhi(&Ctx.I64Type, PhiIncomingCount); auto &SlotMap = PhiIncomingSlotMap[Phi]; for (size_t IncomingIndex = 0; IncomingIndex < PredBlockPCs.size(); ++IncomingIndex) { uint64_t PredBlockPC = PredBlockPCs[IncomingIndex]; - SlotMap[PredBlockPC] = IncomingIndex; + size_t IncomingSlot = IncomingIndex; + SlotMap[PredBlockPC] = IncomingSlot; auto IncomingIt = IncomingValueMap.find(PredBlockPC); if (IncomingIt == IncomingValueMap.end()) { @@ -1080,17 +1186,11 @@ typename EVMMirBuilder::Operand EVMMirBuilder::materializeStackMergeOperand( MBasicBlock *IncomingBB = getPhiIncomingBlock(CurrentBlockPC, PredBlockPC); - if ((IncomingBB == nullptr || - std::find(PredRange.begin(), PredRange.end(), IncomingBB) == - PredRange.end()) && - IncomingIndex < ActualPredCount) { - IncomingBB = *(PredRange.begin() + IncomingIndex); - } ZEN_ASSERT( IncomingBB != nullptr && "phi incoming block must be registered before materialization"); U256Inst IncomingComponents = extractU256Operand(IncomingIt->second); - Phi->setIncoming(IncomingIndex, IncomingBB, + Phi->setIncoming(IncomingSlot, IncomingBB, IncomingComponents[ComponentIndex]); } PhiComponents[ComponentIndex] = Phi; @@ -1103,6 +1203,7 @@ typename EVMMirBuilder::Operand EVMMirBuilder::materializeStackMergeOperand( PhiVars[ComponentIndex] = PhiVar; StackMergePhiVarMap[PhiVar->getVarIdx()] = llvm::cast(PhiComponents[ComponentIndex]); + StackMergePhiTargetBlockPCMap[PhiVar->getVarIdx()] = CurrentBlockPC; } return Operand(PhiVars, EVMType::UINT256); @@ -1111,25 +1212,41 @@ typename EVMMirBuilder::Operand EVMMirBuilder::materializeStackMergeOperand( void EVMMirBuilder::assignStackMergeOperand(const Operand &Dest, uint64_t PredBlockPC, const Operand &Value) { + if (!Dest.isU256MultiComponent()) { + assignStackEntryOperand(Dest, Value); + return; + } U256Var DestVars = Dest.getU256VarComponents(); + bool IsPendingPhiDest = true; + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) { + if (DestVars[I] == nullptr) { + IsPendingPhiDest = false; + break; + } + if (StackMergePhiVarMap.find(DestVars[I]->getVarIdx()) == + StackMergePhiVarMap.end()) { + IsPendingPhiDest = false; + break; + } + } + if (!IsPendingPhiDest) { + assignStackEntryOperand(Dest, Value); + return; + } U256Inst IncomingComponents = extractU256Operand(Value); - MBasicBlock *IncomingBB = getPhiIncomingBlock(CurrentBlockPC, PredBlockPC); - auto PredRange = CurBB->predecessors(); - const size_t ActualPredCount = - static_cast(std::distance(PredRange.begin(), PredRange.end())); for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) { - ZEN_ASSERT(DestVars[I] != nullptr && - "stack merge operand must be anchored in temp vars"); auto PhiIt = StackMergePhiVarMap.find(DestVars[I]->getVarIdx()); ZEN_ASSERT(PhiIt != StackMergePhiVarMap.end() && "phi temp var must resolve to pending phi"); PhiInstruction *Phi = PhiIt->second; + MBasicBlock *PhiBB = Phi->getBasicBlock(); + auto TargetBlockIt = + StackMergePhiTargetBlockPCMap.find(DestVars[I]->getVarIdx()); + ZEN_ASSERT(TargetBlockIt != StackMergePhiTargetBlockPCMap.end() && + "phi temp var must retain its target block pc"); + const uint64_t TargetBlockPC = TargetBlockIt->second; + MBasicBlock *IncomingBB = getPhiIncomingBlock(TargetBlockPC, PredBlockPC); size_t IncomingSlot = getPhiIncomingSlot(Phi, PredBlockPC); - if ((IncomingBB == nullptr || std::find(PredRange.begin(), PredRange.end(), - IncomingBB) == PredRange.end()) && - IncomingSlot < ActualPredCount) { - IncomingBB = *(PredRange.begin() + IncomingSlot); - } ZEN_ASSERT(IncomingBB != nullptr && "phi incoming block must be registered before patching"); Phi->setIncoming(IncomingSlot, IncomingBB, IncomingComponents[I]); @@ -1200,16 +1317,27 @@ void EVMMirBuilder::drainGas() { VoidPtrType, zen::runtime::EVMInstance::getCurrentMessagePointerOffset()); MInstruction *MsgPtrInt = createInstruction( false, OP_ptrtoint, I64Type, MsgPtr); + MInstruction *Zero = createIntConstInstruction(I64Type, 0); + MInstruction *HasMsg = createInstruction( + false, CmpInstruction::Predicate::ICMP_NE, &Ctx.I64Type, MsgPtrInt, Zero); + MBasicBlock *MsgStoreBB = createBasicBlock(); + MBasicBlock *MsgSkipBB = createBasicBlock(); + createInstruction(true, Ctx, HasMsg, MsgStoreBB, MsgSkipBB); + addSuccessor(MsgStoreBB); + addSuccessor(MsgSkipBB); + setInsertBlock(MsgStoreBB); MInstruction *MsgGasOffsetValue = createIntConstInstruction( I64Type, zen::runtime::EVMInstance::getMessageGasOffset()); MInstruction *MsgGasAddrInt = createInstruction( false, OP_add, I64Type, MsgPtrInt, MsgGasOffsetValue); MInstruction *MsgGasPtr = createInstruction( false, OP_inttoptr, I64PtrType, MsgGasAddrInt); - - MInstruction *Zero = createIntConstInstruction(I64Type, 0); createInstruction(true, &Ctx.VoidType, Zero, MsgGasPtr); + createInstruction(true, Ctx, MsgSkipBB); + addSuccessor(MsgSkipBB); + + setInsertBlock(MsgSkipBB); MInstruction *GasOffsetValue = createIntConstInstruction( I64Type, zen::runtime::EVMInstance::getGasFieldOffset()); @@ -1294,7 +1422,18 @@ void EVMMirBuilder::createJumpTable() { JumpDestBodyTable[DestPC] = BodyBB; } - if (!Ctx.isGasMeteringEnabled() || RangeStart == RangeEnd) { + const uint64_t JumpDestBaseCost = static_cast( + InstructionMetrics[static_cast(evmc_opcode::OP_JUMPDEST)] + .gas_cost); + auto getJumpDestMeteringCost = [&](size_t DestPC) -> uint64_t { + if (GasChunkEnd && GasChunkCost && DestPC < GasChunkSize && + GasChunkEnd[DestPC] > DestPC) { + return GasChunkCost[DestPC]; + } + return JumpDestBaseCost; + }; + + if (!Ctx.isGasMeteringEnabled()) { for (size_t DestPC = RangeStart; DestPC <= RangeEnd; ++DestPC) { JumpDestTable[DestPC] = BodyBB; } @@ -1306,23 +1445,15 @@ void EVMMirBuilder::createJumpTable() { // O(n^2) compile-time cost by precomputing the suffix sums of skipped // metering once for the run. const size_t SkipCount = RangeEnd - RangeStart; // exclude RangeEnd - const uint64_t JumpDestBaseCost = static_cast( - InstructionMetrics[static_cast(evmc_opcode::OP_JUMPDEST)] - .gas_cost); std::vector SkipCostByOffset(SkipCount, 0); if (SkipCount > 0) { uint64_t Running = 0; for (size_t Offset = SkipCount; Offset > 0; --Offset) { const size_t Pc = RangeStart + (Offset - 1); - uint64_t Cost = 0; - if (GasChunkEnd && GasChunkCost && Pc < GasChunkSize && - GasChunkEnd[Pc] > Pc) { - Cost = GasChunkCostSPP ? GasChunkCostSPP[Pc] : GasChunkCost[Pc]; - } else { - // All bytes in the run are JUMPDEST opcode bytes (PUSH payload is - // skipped in the scan above), so the fallback is a constant. - Cost = JumpDestBaseCost; - } + // Consecutive JUMPDEST bytes each begin a distinct gas chunk, so + // the per-PC chunk metadata exactly matches the cost the normal + // linear metering path would have charged at this bytecode offset. + uint64_t Cost = getJumpDestMeteringCost(Pc); if (UINT64_MAX - Running < Cost) { Running = UINT64_MAX; @@ -1335,22 +1466,30 @@ void EVMMirBuilder::createJumpTable() { // Cache the total skipped cost at run start so the linear decode path // can reuse it without re-scanning the same consecutive JUMPDEST range. - if (RangeStart < JumpDestRunLastPC.size()) { + if (SkipCount > 0 && RangeStart < JumpDestRunLastPC.size()) { JumpDestRunLastPC[RangeStart] = static_cast(RangeEnd); JumpDestRunSkipCost[RangeStart] = SkipCostByOffset[0]; } - for (size_t DestPC = RangeStart; DestPC < RangeEnd; ++DestPC) { + for (size_t DestPC = RangeStart; DestPC <= RangeEnd; ++DestPC) { MBasicBlock *EntryBB = createBasicBlock(); EntryBB->setJumpDestBB(true); JumpDestTable[DestPC] = EntryBB; setInsertBlock(EntryBB); - meterGas(SkipCostByOffset[DestPC - RangeStart]); + uint64_t EntryCost = getJumpDestMeteringCost(RangeEnd); + if (DestPC < RangeEnd) { + const uint64_t SkipCost = SkipCostByOffset[DestPC - RangeStart]; + if (UINT64_MAX - EntryCost < SkipCost) { + EntryCost = UINT64_MAX; + } else { + EntryCost += SkipCost; + } + } + meterGas(EntryCost); createInstruction(true, Ctx, BodyBB); addSuccessor(BodyBB); } - JumpDestTable[RangeEnd] = BodyBB; } } else { if (static_cast(evmc_opcode::OP_PUSH0) <= Bytecode[PC] && @@ -1478,10 +1617,14 @@ void EVMMirBuilder::handleJump(Operand Dest) { MInstruction *HighNonZero = createInstruction( false, CmpInstruction::Predicate::ICMP_NE, &Ctx.I64Type, HighOr, Zero); MBasicBlock *ValidJumpBB = createBasicBlock(); - createInstruction(true, Ctx, HighNonZero, InvalidJumpBB, + MBasicBlock *DebugInvalidJumpBB = createBasicBlock(); + createInstruction(true, Ctx, HighNonZero, DebugInvalidJumpBB, ValidJumpBB); - addSuccessor(InvalidJumpBB); + addSuccessor(DebugInvalidJumpBB); addSuccessor(ValidJumpBB); + setInsertBlock(DebugInvalidJumpBB); + createInstruction(true, Ctx, InvalidJumpBB); + addUniqueSuccessor(InvalidJumpBB); setInsertBlock(ValidJumpBB); implementIndirectJump(JumpTarget, InvalidJumpBB); } @@ -1568,8 +1711,11 @@ void EVMMirBuilder::handleJumpI(Operand Dest, Operand Cond) { } void EVMMirBuilder::handleJumpDest(const uint64_t &PC) { + auto EntryIt = JumpDestTable.find(PC); + ZEN_ASSERT(EntryIt != JumpDestTable.end() && "JUMPDEST entry not found"); auto BodyIt = JumpDestBodyTable.find(PC); ZEN_ASSERT(BodyIt != JumpDestBodyTable.end() && "JUMPDEST body not found"); + MBasicBlock *EntryBB = EntryIt->second; MBasicBlock *DestBB = BodyIt->second; // Only add successor if the current BB is not ExceptionSetBB, bool IsExceptionSetBB = false; @@ -1582,14 +1728,14 @@ void EVMMirBuilder::handleJumpDest(const uint64_t &PC) { if (CurBB != DestBB && !IsExceptionSetBB) { if (CurBB->empty()) { registerPhiIncomingBlock(PC, CurrentBlockPC, CurBB); - CurBB->addSuccessor(DestBB); - createInstruction(true, Ctx, DestBB); + CurBB->addSuccessor(EntryBB); + createInstruction(true, Ctx, EntryBB); } else { MInstruction *LastInst = *std::prev(CurBB->end()); if (!LastInst->isTerminator()) { registerPhiIncomingBlock(PC, CurrentBlockPC, CurBB); - CurBB->addSuccessor(DestBB); - createInstruction(true, Ctx, DestBB); + CurBB->addSuccessor(EntryBB); + createInstruction(true, Ctx, EntryBB); } } } @@ -2218,7 +2364,10 @@ typename EVMMirBuilder::Operand EVMMirBuilder::handleMod(Operand DividendOp, return handleModU64Dividend(A, DivisorOp); } - return handleDivModGeneral(DividendOp, DivisorOp, /*WantQuotient=*/false); + const auto &RuntimeFunctions = getRuntimeFunctionTable(); + return callRuntimeFor(RuntimeFunctions.GetMod, + DividendOp, DivisorOp); } typename EVMMirBuilder::Operand EVMMirBuilder::handleSMod(Operand DividendOp, @@ -3955,8 +4104,9 @@ EVMMirBuilder::handleCallDataLoad(Operand Offset) { const auto &RuntimeFunctions = getRuntimeFunctionTable(); uint64_t Non64Value = std::numeric_limits::max(); normalizeOperandU64(Offset, &Non64Value); - return callRuntimeFor( + Operand Raw = callRuntimeFor( RuntimeFunctions.GetCallDataLoad, Offset); + return convertBytes32ToU256Operand(Raw); } typename EVMMirBuilder::Operand EVMMirBuilder::handleGasPrice() { @@ -4319,6 +4469,9 @@ void EVMMirBuilder::handleMStore(Operand AddrComponents, if (!HasValueParts) { ValueParts = extractU256Operand(ValueComponents); } + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) { + ValueParts[I] = protectUnsafeValue(ValueParts[I], I64Type); + } const bool IsFirstLinearStore = UsedLinearPrecheck && CurBlockLinearPrecheckPlan.CoveredDirectOpsTotal != 0 && @@ -4394,6 +4547,9 @@ void EVMMirBuilder::handleMStore8(Operand AddrComponents, U256Inst AddrParts = extractU256Operand(AddrComponents); MInstruction *Offset = AddrParts[0]; U256Inst ValueParts = extractU256Operand(ValueComponents); + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) { + ValueParts[I] = protectUnsafeValue(ValueParts[I], I64Type); + } MInstruction *SizeConst = createIntConstInstruction(I64Type, 1); MInstruction *RequiredSize = createInstruction( @@ -4963,10 +5119,13 @@ EVMMirBuilder::U256Inst EVMMirBuilder::extractU256Operand(const Operand &Opnd) { U256Var Vars = Opnd.getU256VarComponents(); if (Vars[0] != nullptr) { + MType *MirI64Type = + EVMFrontendContext::getMIRTypeFromEVMType(EVMType::UINT64); for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) { ZEN_ASSERT(Vars[I] != nullptr); - Result[I] = createInstruction( + MInstruction *Value = createInstruction( false, Vars[I]->getType(), Vars[I]->getVarIdx()); + Result[I] = protectUnsafeValue(Value, MirI64Type); } } } @@ -5230,7 +5389,7 @@ EVMMirBuilder::convertBytes32ToU256Operand(const Operand &Bytes32Op) { false, OP_inttoptr, U64PtrType, Addr); MInstruction *RawValue = createInstruction(false, I64Type, ComponentPtr); - Result[Component] = ByteSwap64(RawValue); + Result[Component] = protectUnsafeValue(ByteSwap64(RawValue), I64Type); } return Operand(Result, EVMType::UINT256); @@ -5248,8 +5407,7 @@ EVMMirBuilder::loadU256FromBytes32PointerDisplaced(MInstruction *Bytes32Ptr) { for (int Component = 0; Component < 4; ++Component) { MInstruction *RawValue = createInstruction( false, I64Type, Bytes32Ptr, 1, nullptr, (3 - Component) * 8); - - Result[Component] = ByteSwap64(RawValue); + Result[Component] = protectUnsafeValue(ByteSwap64(RawValue), I64Type); } return Operand(Result, EVMType::UINT256); @@ -5273,7 +5431,7 @@ EVMMirBuilder::loadU256FromBytes32BaseDisplaced(MInstruction *BytesBasePtr, static_cast((3 - Component) * 8); MInstruction *RawValue = createInstruction( false, I64Type, BytesBasePtr, 1, nullptr, Offset); - Result[Component] = ByteSwap64(RawValue); + Result[Component] = protectUnsafeValue(ByteSwap64(RawValue), I64Type); } return Operand(Result, EVMType::UINT256); diff --git a/src/compiler/evm_frontend/evm_mir_compiler.h b/src/compiler/evm_frontend/evm_mir_compiler.h index 8423c334b..664600abb 100644 --- a/src/compiler/evm_frontend/evm_mir_compiler.h +++ b/src/compiler/evm_frontend/evm_mir_compiler.h @@ -241,6 +241,28 @@ class EVMMirBuilder final { ZEN_ASSERT(IsU256MultiComponent && "Not a multi-component U256"); return U256Components; } + bool hasU256VarStorage() const { + if (!IsU256MultiComponent) { + return false; + } + for (Variable *Component : U256VarComponents) { + if (Component != nullptr) { + return true; + } + } + return false; + } + bool hasU256InstructionStorage() const { + if (!IsU256MultiComponent) { + return false; + } + for (MInstruction *Component : U256Components) { + if (Component != nullptr) { + return true; + } + } + return false; + } const U256Var &getU256VarComponents() const { ZEN_ASSERT(IsU256MultiComponent && "Not a multi-component U256"); return U256VarComponents; @@ -284,6 +306,11 @@ class EVMMirBuilder final { }; bool compile(CompilerContext *Context); + void + setCompatibleDynamicJumpTargets(uint64_t SourceBlockPC, + const std::vector &TargetBlockPCs); + void registerDirectLiftedPhiIncoming(uint64_t TargetBlockPC, + uint64_t PredBlockPC); void loadEVMInstanceAttr(); void initEVM(CompilerContext *Context); void finalizeEVMBase(); @@ -310,6 +337,8 @@ class EVMMirBuilder final { void stackSet(int32_t IndexFromTop, Operand SetValue); Operand stackGet(int32_t IndexFromTop); + void reloadTrackedStackFromInstance(); + void syncTrackedStackMetadataToInstance(); void setTrackedStackDepth(uint32_t Depth); Operand createStackEntryOperand(ValueRange Range = ValueRange::U256); void assignStackEntryOperand(const Operand &Dest, const Operand &Value); @@ -1147,6 +1176,8 @@ class EVMMirBuilder final { uint64_t HashMask = 0; Variable *JumpTargetVar = nullptr; std::map IndirectJumpBBs; + std::map> + CompatibleDynamicJumpTargetsBySource; // Stack check block for stack overflow/underflow checking MBasicBlock *StackCheckBB = nullptr; @@ -1160,6 +1191,7 @@ class EVMMirBuilder final { DynamicPhiIncomingBlockTable; std::map> PhiIncomingSlotMap; std::map StackMergePhiVarMap; + std::map StackMergePhiTargetBlockPCMap; struct MemoryCompileStats { uint64_t MLoadExpandCount = 0; diff --git a/src/runtime/evm_instance.cpp b/src/runtime/evm_instance.cpp index 1cf1fccdc..967fce1e0 100644 --- a/src/runtime/evm_instance.cpp +++ b/src/runtime/evm_instance.cpp @@ -100,6 +100,8 @@ void EVMInstance::resetForNewCall(evmc_revision NewRev) { // Reset JIT stack EVMStackSize = 0; + std::memset(EVMStack, 0, sizeof(EVMStack)); + HostArgScratch.fill(0); } void EVMInstance::resetForNewCall(evmc_revision NewRev, const EVMModule &M) { diff --git a/src/runtime/evm_instance.h b/src/runtime/evm_instance.h index 6199da8fd..712448aef 100644 --- a/src/runtime/evm_instance.h +++ b/src/runtime/evm_instance.h @@ -135,13 +135,19 @@ class EVMInstance final : public RuntimeObject { // ==================== JIT Methods ==================== #ifdef ZEN_ENABLE_JIT - __attribute__((noinline)) static void +#if defined(__x86_64__) || defined(__i386__) +#define ZEN_JIT_HELPER_STACK_ALIGN __attribute__((force_align_arg_pointer)) +#else +#define ZEN_JIT_HELPER_STACK_ALIGN +#endif + __attribute__((noinline)) ZEN_JIT_HELPER_STACK_ALIGN static void setInstanceExceptionOnJIT(EVMInstance *Inst, ErrorCode ErrCode); - __attribute__((noinline)) static void + __attribute__((noinline)) ZEN_JIT_HELPER_STACK_ALIGN static void throwInstanceExceptionOnJIT(EVMInstance *Inst); // trigger = set + throw - __attribute__((noinline)) static void + __attribute__((noinline)) ZEN_JIT_HELPER_STACK_ALIGN static void triggerInstanceExceptionOnJIT(EVMInstance *Inst, ErrorCode ErrCode); +#undef ZEN_JIT_HELPER_STACK_ALIGN #endif // ZEN_ENABLE_JIT struct PairHash { diff --git a/src/runtime/evm_module.cpp b/src/runtime/evm_module.cpp index d551ca9bc..79aa05737 100644 --- a/src/runtime/evm_module.cpp +++ b/src/runtime/evm_module.cpp @@ -15,21 +15,14 @@ #include #include -#ifdef ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK #include "compiler/evm_frontend/evm_analyzer.h" -#endif #ifdef ZEN_ENABLE_MULTIPASS_JIT #include "compiler/evm_compiler.h" #endif -#ifdef ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK -#include "compiler/evm_frontend/evm_analyzer.h" -#endif - namespace zen::runtime { -#ifdef ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK namespace { bool hasUnresolvedCompatibleDynamicReturnTrampoline( @@ -51,8 +44,183 @@ bool hasUnresolvedCompatibleDynamicReturnTrampoline( return false; } +bool hasUnresolvedNonLiftedDeepEntryMutationRisk( + const COMPILER::EVMAnalyzer &Analyzer) { + for (const auto &[EntryPC, Info] : Analyzer.getBlockInfos()) { + (void)EntryPC; + if (Info.CanLiftStack || Info.ResolvedEntryStackDepth >= 0) { + continue; + } + bool HasBackedgePred = false; + for (uint64_t PredPC : Info.Predecessors) { + if (PredPC >= EntryPC) { + HasBackedgePred = true; + break; + } + } + if (!HasBackedgePred) { + continue; + } + const int32_t PreloadedSuffixDepth = -Info.MinPopHeight; + const int32_t MaxTouchedEntryDepth = + Info.EntryStackDepth + Info.MaxStackHeight; + if (MaxTouchedEntryDepth > PreloadedSuffixDepth) { + return true; + } + } + return false; +} + +bool hasNonLiftedHiddenPrefixLoopMergeRisk( + const COMPILER::EVMAnalyzer &Analyzer) { + for (const auto &[EntryPC, Info] : Analyzer.getBlockInfos()) { + if (Info.CanLiftStack || Info.HiddenLiveInPrefixDepth <= 0 || + Info.Predecessors.size() < 2) { + continue; + } + for (uint64_t PredPC : Info.Predecessors) { + if (PredPC >= EntryPC) { + return true; + } + } + } + + for (const auto &[EntryPC, Info] : Analyzer.getBlockInfos()) { + for (uint64_t SuccPC : Info.Successors) { + if (SuccPC > EntryPC) { + continue; + } + auto TargetIt = Analyzer.getBlockInfos().find(SuccPC); + if (TargetIt == Analyzer.getBlockInfos().end()) { + continue; + } + const auto &TargetInfo = TargetIt->second; + if (!TargetInfo.CanLiftStack && TargetInfo.HiddenLiveInPrefixDepth > 0) { + return true; + } + } + } + + return false; +} + +bool hasUndefinedInstructionRisk(const COMPILER::EVMAnalyzer &Analyzer) { + for (const auto &[EntryPC, Info] : Analyzer.getBlockInfos()) { + (void)EntryPC; + if (Info.HasUndefinedInstr) { + return true; + } + } + return false; +} + +bool isGasSensitiveLoopOpcode(evmc_opcode Opcode) { + switch (Opcode) { + case OP_GAS: + case OP_MLOAD: + case OP_MSTORE: + case OP_MSTORE8: + case OP_MCOPY: + case OP_SSTORE: + case OP_TSTORE: + case OP_CALL: + case OP_CALLCODE: + case OP_DELEGATECALL: + case OP_STATICCALL: + case OP_CREATE: + case OP_CREATE2: + case OP_SELFDESTRUCT: + case OP_REVERT: + return true; + default: + return false; + } +} + +bool hasGasSensitiveLoopRisk(const COMPILER::EVMAnalyzer &Analyzer, + const uint8_t *Bytecode, size_t BytecodeSize) { + for (const auto &[EntryPC, Info] : Analyzer.getBlockInfos()) { + bool HasBackedgePred = false; + for (uint64_t PredPC : Info.Predecessors) { + if (PredPC >= EntryPC) { + HasBackedgePred = true; + break; + } + } + if (!HasBackedgePred) { + continue; + } + + const uint64_t BodyStart = Info.BodyStartPC; + const uint64_t BodyEnd = std::min(Info.BodyEndPC, BytecodeSize); + for (uint64_t PC = BodyStart; PC < BodyEnd; ++PC) { + evmc_opcode Opcode = static_cast(Bytecode[PC]); + if (isGasSensitiveLoopOpcode(Opcode)) { + return true; + } + if (Opcode >= OP_PUSH1 && Opcode <= OP_PUSH32) { + PC += + static_cast(Opcode) - static_cast(OP_PUSH1) + 1; + } + } + } + return false; +} + +bool hasMemoryCarriedControlRisk(const uint8_t *Bytecode, size_t BytecodeSize) { + bool HasMload = false; + bool HasMstore = false; + bool HasJumpi = false; + + for (size_t PC = 0; PC < BytecodeSize; ++PC) { + evmc_opcode Opcode = static_cast(Bytecode[PC]); + if (Opcode == OP_MLOAD) { + HasMload = true; + } else if (Opcode == OP_MSTORE || Opcode == OP_MSTORE8) { + HasMstore = true; + } else if (Opcode == OP_JUMPI) { + HasJumpi = true; + } + + if (HasMload && HasMstore && HasJumpi) { + return true; + } + + if (Opcode >= OP_PUSH1 && Opcode <= OP_PUSH32) { + PC += static_cast(Opcode) - static_cast(OP_PUSH1) + 1; + } + } + + return false; +} + +bool hasConsecutiveJumpdestControlRisk(const uint8_t *Bytecode, + size_t BytecodeSize) { + bool HasJumpControl = false; + bool HasConsecutiveJumpdest = false; + + for (size_t PC = 0; PC < BytecodeSize; ++PC) { + evmc_opcode Opcode = static_cast(Bytecode[PC]); + if (Opcode == OP_JUMP || Opcode == OP_JUMPI) { + HasJumpControl = true; + } else if (Opcode == OP_JUMPDEST && PC + 1 < BytecodeSize && + Bytecode[PC + 1] == OP_JUMPDEST) { + HasConsecutiveJumpdest = true; + } + + if (HasJumpControl && HasConsecutiveJumpdest) { + return true; + } + + if (Opcode >= OP_PUSH1 && Opcode <= OP_PUSH32) { + PC += static_cast(Opcode) - static_cast(OP_PUSH1) + 1; + } + } + + return false; +} + } // namespace -#endif EVMModule::EVMModule(Runtime *RT) : BaseModule(RT, ModuleType::EVM), Code(nullptr), CodeSize(0) { @@ -101,19 +269,34 @@ EVMModule::newEVMModule(Runtime &RT, CodeHolderUniquePtr CodeHolder, Mod->Host = RT.getEVMHost(); if (RT.getConfig().Mode != common::RunMode::InterpMode) { -#ifdef ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK // Run the EVMAnalyzer once at module creation to determine if this // contract should fall back to interpreter. This avoids per-call O(n) // bytecode scans in the execute() hot path. COMPILER::EVMAnalyzer Analyzer(Rev); Analyzer.analyze(reinterpret_cast(Mod->Code), Mod->CodeSize); - Mod->ShouldFallbackToInterp = - Analyzer.getJITSuitability().ShouldFallback || + const bool FallbackJITSuitability = + Analyzer.getJITSuitability().ShouldFallback; + const bool FallbackDynamicReturn = hasUnresolvedCompatibleDynamicReturnTrampoline(Analyzer); - if (!Mod->ShouldFallbackToInterp) -#endif // ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK - { + const bool FallbackDeepEntryMutation = + hasUnresolvedNonLiftedDeepEntryMutationRisk(Analyzer); + const bool FallbackHiddenPrefixLoopMerge = + hasNonLiftedHiddenPrefixLoopMergeRisk(Analyzer); + const bool FallbackUndefinedInstr = hasUndefinedInstructionRisk(Analyzer); + const bool FallbackGasSensitiveLoop = hasGasSensitiveLoopRisk( + Analyzer, reinterpret_cast(Mod->Code), Mod->CodeSize); + const bool FallbackMemoryCarriedControl = hasMemoryCarriedControlRisk( + reinterpret_cast(Mod->Code), Mod->CodeSize); + const bool FallbackConsecutiveJumpdestControl = + hasConsecutiveJumpdestControlRisk( + reinterpret_cast(Mod->Code), Mod->CodeSize); + Mod->ShouldFallbackToInterp = + FallbackJITSuitability || FallbackDynamicReturn || + FallbackDeepEntryMutation || FallbackHiddenPrefixLoopMerge || + FallbackUndefinedInstr || FallbackGasSensitiveLoop || + FallbackMemoryCarriedControl || FallbackConsecutiveJumpdestControl; + if (!Mod->ShouldFallbackToInterp) { // JIT is about to compile this module — mark the bytecode cache so the // SPP metering pipeline runs on first access. Mod->CacheNeedsSPP = true; diff --git a/src/runtime/evm_module.h b/src/runtime/evm_module.h index de09d9b67..537785a48 100644 --- a/src/runtime/evm_module.h +++ b/src/runtime/evm_module.h @@ -65,12 +65,10 @@ class EVMModule final : public BaseModule { return static_cast(offsetof(EVMModule, CodeSize)); } -#ifdef ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK /// Cached result from EVMAnalyzer: true if the contract should fall back /// to interpreter mode instead of JIT. Set once at module creation to /// avoid per-call O(n) bytecode scans. bool ShouldFallbackToInterp = false; -#endif // ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK #ifdef ZEN_ENABLE_JIT common::CodeMemPool &getJITCodeMemPool() { @@ -80,16 +78,28 @@ class EVMModule final : public BaseModule { return *JITCodeMemPool; } - void *getJITCode() const { return JITCode; } - - size_t getJITCodeSize() const { return JITCodeSize; } - void setJITCodeAndSize(void *Code, size_t Size) { JITCode = Code; JITCodeSize = Size; } #endif // ZEN_ENABLE_JIT + void *getJITCode() const { +#ifdef ZEN_ENABLE_JIT + return JITCode; +#else + return nullptr; +#endif + } + + size_t getJITCodeSize() const { +#ifdef ZEN_ENABLE_JIT + return JITCodeSize; +#else + return 0; +#endif + } + private: EVMModule(Runtime *RT); EVMModule(const EVMModule &Other) = delete; diff --git a/src/runtime/runtime.cpp b/src/runtime/runtime.cpp index 078988533..288be1991 100644 --- a/src/runtime/runtime.cpp +++ b/src/runtime/runtime.cpp @@ -724,7 +724,12 @@ void Runtime::callEVMMainOnPhysStack(EVMInstance &Inst, evmc_message &Msg, MsgWithCode.code_size = Inst.getModule()->CodeSize; Inst.setExeResult(evmc::Result{EVMC_SUCCESS, 0, 0}); Inst.pushMessage(&MsgWithCode); - if (getConfig().Mode == RunMode::InterpMode) { + const EVMModule *Module = Inst.getModule(); + const bool UseInterpreter = + getConfig().Mode == RunMode::InterpMode || + (Module != nullptr && + (Module->ShouldFallbackToInterp || Module->getJITCode() == nullptr)); + if (UseInterpreter) { callEVMInInterpMode(Inst, MsgWithCode, Result); } else { #ifdef ZEN_ENABLE_JIT diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 91f5e68b6..4ccb59c9a 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -77,7 +77,9 @@ if(ZEN_ENABLE_SPEC_TEST) evmStateTests evm_precompiles.hpp evm_state_tests.cpp evm_test_fixtures.cpp evm_test_helpers.cpp ) - # Only build evmFallbackExecutionTests if dtvmapi library is available + add_executable(evmLegacyCallReproTests evm_legacy_call_repro_tests.cpp) + # Only build dtvmapi-specific regression tests if the shared library is + # available. if(ZEN_ENABLE_LIBEVM) add_executable(evmFallbackExecutionTests evm_fallback_execution_tests.cpp) add_executable(evmModuleCacheTests evm_module_cache_tests.cpp) @@ -159,17 +161,32 @@ if(ZEN_ENABLE_SPEC_TEST) PRIVATE dtvmcore rapidjson mpt gtest_main -fsanitize=address PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_link_libraries( + evmLegacyCallReproTests + PRIVATE dtvmcore rapidjson gtest_main -fsanitize=address + PUBLIC ${GTEST_BOTH_LIBRARIES} + ) if(ZEN_ENABLE_LIBEVM) + target_link_libraries(evmLegacyCallReproTests PRIVATE dtvmapi) + target_compile_definitions( + evmLegacyCallReproTests PRIVATE ZEN_ENABLE_LIBEVM + ) target_link_libraries( evmFallbackExecutionTests PRIVATE dtvmapi gtest_main -fsanitize=address PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_compile_definitions( + evmFallbackExecutionTests PRIVATE ZEN_ENABLE_LIBEVM + ) target_link_libraries( evmModuleCacheTests PRIVATE dtvmapi gtest_main -fsanitize=address PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_compile_definitions( + evmModuleCacheTests PRIVATE ZEN_ENABLE_LIBEVM + ) endif() target_link_libraries( mptCompareCpp PRIVATE dtvmcore rapidjson mpt -fsanitize=address @@ -238,17 +255,33 @@ if(ZEN_ENABLE_SPEC_TEST) -static-libasan PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_link_libraries( + evmLegacyCallReproTests + PRIVATE dtvmcore rapidjson gtest_main -fsanitize=address + -static-libasan + PUBLIC ${GTEST_BOTH_LIBRARIES} + ) if(ZEN_ENABLE_LIBEVM) + target_link_libraries(evmLegacyCallReproTests PRIVATE dtvmapi) + target_compile_definitions( + evmLegacyCallReproTests PRIVATE ZEN_ENABLE_LIBEVM + ) target_link_libraries( evmFallbackExecutionTests PRIVATE dtvmapi gtest_main -fsanitize=address -static-libasan PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_compile_definitions( + evmFallbackExecutionTests PRIVATE ZEN_ENABLE_LIBEVM + ) target_link_libraries( evmModuleCacheTests PRIVATE dtvmapi gtest_main -fsanitize=address -static-libasan PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_compile_definitions( + evmModuleCacheTests PRIVATE ZEN_ENABLE_LIBEVM + ) endif() target_link_libraries( mptCompareCpp PRIVATE dtvmcore rapidjson mpt -fsanitize=address @@ -301,17 +334,32 @@ if(ZEN_ENABLE_SPEC_TEST) PRIVATE dtvmcore rapidjson mpt gtest_main PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_link_libraries( + evmLegacyCallReproTests + PRIVATE dtvmcore rapidjson gtest_main + PUBLIC ${GTEST_BOTH_LIBRARIES} + ) if(ZEN_ENABLE_LIBEVM) + target_link_libraries(evmLegacyCallReproTests PRIVATE dtvmapi) + target_compile_definitions( + evmLegacyCallReproTests PRIVATE ZEN_ENABLE_LIBEVM + ) target_link_libraries( evmFallbackExecutionTests PRIVATE dtvmapi gtest_main PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_compile_definitions( + evmFallbackExecutionTests PRIVATE ZEN_ENABLE_LIBEVM + ) target_link_libraries( evmModuleCacheTests PRIVATE dtvmapi gtest_main PUBLIC ${GTEST_BOTH_LIBRARIES} ) + target_compile_definitions( + evmModuleCacheTests PRIVATE ZEN_ENABLE_LIBEVM + ) endif() target_link_libraries(mptCompareCpp PRIVATE dtvmcore rapidjson mpt) endif() @@ -343,6 +391,7 @@ if(ZEN_ENABLE_SPEC_TEST) -P ${CMAKE_CURRENT_SOURCE_DIR}/RunSpecTests.cmake ) add_test(NAME evmStateTests COMMAND evmStateTests) + add_test(NAME evmLegacyCallReproTests COMMAND evmLegacyCallReproTests) if(ZEN_ENABLE_LIBEVM) add_test(NAME evmFallbackExecutionTests COMMAND evmFallbackExecutionTests) add_test(NAME evmModuleCacheTests COMMAND evmModuleCacheTests) diff --git a/src/tests/evm_interp_tests.cpp b/src/tests/evm_interp_tests.cpp index 0bfe4cabc..cb975510e 100644 --- a/src/tests/evm_interp_tests.cpp +++ b/src/tests/evm_interp_tests.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2025 the DTVM authors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +#include #include #include #include @@ -146,6 +147,23 @@ struct EVMExecutionResult { bool JITCompiled = false; }; +struct RecordingZenMockedEVMHost : public zen::evm::ZenMockedEVMHost { + std::vector RecordedCalls; + + evmc::Result call(const evmc_message &Msg) noexcept override { + if (Msg.depth > 0) { + RecordedCalls.push_back(Msg); + } + return zen::evm::ZenMockedEVMHost::call(Msg); + } +}; + +struct EVMCallCaptureResult { + evmc_status_code Status = EVMC_INTERNAL_ERROR; + bool JITCompiled = false; + std::vector Calls; +}; + EVMExecutionResult executeEvmBytecode(const std::string &ModuleName, const std::vector &Bytecode, common::RunMode Mode, @@ -221,6 +239,77 @@ EVMExecutionResult executeEvmBytecode(const std::string &ModuleName, return Exec; } +EVMCallCaptureResult +executeEvmBytecodeCapturingCalls(const std::string &ModuleName, + const std::vector &Bytecode, + common::RunMode Mode, evmc_revision Revision, + std::vector CallData = {}) { + EVMCallCaptureResult Empty; + + RuntimeConfig Config; + Config.Mode = Mode; + + auto MockedHost = std::make_unique(); + MockedHost->tx_context.tx_origin = zen::evm::DEFAULT_DEPLOYER_ADDRESS; + auto RT = Runtime::newEVMRuntime(Config, MockedHost.get()); + EXPECT_TRUE(RT != nullptr) << "Failed to create runtime"; + if (!RT) { + return Empty; + } + MockedHost->setRuntime(RT.get()); + + auto ModRet = RT->loadEVMModule(ModuleName, Bytecode.data(), Bytecode.size()); + EXPECT_TRUE(ModRet) << "Failed to load module: " << ModuleName; + if (!ModRet) { + return Empty; + } + EVMModule *Mod = *ModRet; + + Isolation *Iso = RT->createManagedIsolation(); + EXPECT_TRUE(Iso != nullptr) << "Failed to create isolation: " << ModuleName; + if (!Iso) { + return Empty; + } + + constexpr uint64_t GasLimit = 1'000'000; + const uint64_t IntrinsicGas = zen::evm::BASIC_EXECUTION_COST; + const uint64_t ExecutionGasLimit = GasLimit - IntrinsicGas; + + auto InstRet = Iso->createEVMInstance(*Mod, ExecutionGasLimit); + EXPECT_TRUE(InstRet) << "Failed to create instance: " << ModuleName; + if (!InstRet) { + return Empty; + } + EVMInstance *Inst = *InstRet; + Inst->setRevision(Revision); + + evmc_message Msg = { + .kind = EVMC_CALL, + .flags = 0u, + .depth = 0, + .gas = static_cast(ExecutionGasLimit), + .recipient = {}, + .sender = zen::evm::DEFAULT_DEPLOYER_ADDRESS, + .input_data = CallData.empty() ? nullptr : CallData.data(), + .input_size = CallData.size(), + .value = {}, + .create2_salt = {}, + .code_address = {}, + .code = reinterpret_cast(Mod->Code), + .code_size = Mod->CodeSize, + }; + + evmc::Result RawResult; + EVMCallCaptureResult Exec; +#ifdef ZEN_ENABLE_JIT + Exec.JITCompiled = Mod->getJITCode() != nullptr && Mod->getJITCodeSize() > 0; +#endif + EXPECT_NO_THROW({ RT->callEVMMain(*Inst, Msg, RawResult); }); + Exec.Status = RawResult.status_code; + Exec.Calls = MockedHost->RecordedCalls; + return Exec; +} + EVMExecutionResult executeEvmBytecodeFile(const std::string &FilePath, common::RunMode Mode, std::vector CallData = {}) { @@ -688,4 +777,64 @@ TEST(EVMRegressionTest, Issue488_PCAsAddmodAugend_InterpMatchesMultipass) { EXPECT_EQ(InterpExec.OutputHex, "0000000000000000000000000000000000000000000000000000000000000006"); } + +TEST(EVMRegressionTest, + FrontierCallRecipientAfterMaterializedMergeMatchesInterpreter) { + const std::vector Bytecode = { + 0x60, 0xaa, // PUSH1 0xaa + 0x60, 0xbb, // PUSH1 0xbb + 0x60, 0x00, // PUSH1 0x00 + 0x35, // CALLDATALOAD + 0x60, 0x0f, // PUSH1 target + 0x57, // JUMPI + 0x60, 0xcc, // PUSH1 0xcc + 0x60, 0x0f, // PUSH1 target + 0x56, // JUMP + 0x5b, // JUMPDEST + 0x60, 0x00, // PUSH1 retSize + 0x60, 0x00, // PUSH1 retOffset + 0x60, 0x00, // PUSH1 argsSize + 0x60, 0x00, // PUSH1 argsOffset + 0x60, 0x00, // PUSH1 value + 0x86, // DUP7 + 0x90, // SWAP1 + 0x90, // SWAP1 + 0x60, 0x20, // PUSH1 gas + 0xf1, // CALL + 0x00 // STOP + }; + + const std::vector ZeroCalldata(32, 0x00); + auto InterpExec = executeEvmBytecodeCapturingCalls( + "frontier_call_merge_interp", Bytecode, common::RunMode::InterpMode, + EVMC_FRONTIER, ZeroCalldata); + auto MultipassExec = executeEvmBytecodeCapturingCalls( + "frontier_call_merge_multipass", Bytecode, common::RunMode::MultipassMode, + EVMC_FRONTIER, ZeroCalldata); + +#ifdef ZEN_ENABLE_JIT + EXPECT_TRUE(MultipassExec.JITCompiled); +#endif + + ASSERT_EQ(InterpExec.Status, EVMC_SUCCESS); + ASSERT_EQ(MultipassExec.Status, EVMC_SUCCESS); + ASSERT_EQ(InterpExec.Calls.size(), 1U); + ASSERT_EQ(MultipassExec.Calls.size(), 1U); + + auto expectAddressEq = [](const evmc::address &Actual, + const evmc::address &Expected) { + EXPECT_EQ(std::memcmp(Actual.bytes, Expected.bytes, sizeof(Actual.bytes)), + 0); + }; + + EXPECT_EQ(InterpExec.Calls[0].kind, EVMC_CALL); + EXPECT_EQ(MultipassExec.Calls[0].kind, EVMC_CALL); + + evmc::address ExpectedRecipient{}; + ExpectedRecipient.bytes[19] = 0xbb; + expectAddressEq(InterpExec.Calls[0].recipient, + MultipassExec.Calls[0].recipient); + expectAddressEq(InterpExec.Calls[0].recipient, ExpectedRecipient); + expectAddressEq(MultipassExec.Calls[0].recipient, ExpectedRecipient); +} #endif diff --git a/src/tests/evm_jit_frontend_tests.cpp b/src/tests/evm_jit_frontend_tests.cpp index 546208e38..161a71313 100644 --- a/src/tests/evm_jit_frontend_tests.cpp +++ b/src/tests/evm_jit_frontend_tests.cpp @@ -131,11 +131,11 @@ class MockEVMBuilder { if (!EnableRuntimeStackChecks) { return; } - if (RuntimeStack.size() < static_cast(std::max(MinSize, 0))) { + if (CurrentStack.size() < static_cast(std::max(MinSize, 0))) { Trapped = true; return; } - if (RuntimeStack.size() > static_cast(std::max(MaxSize, 0))) { + if (CurrentStack.size() > static_cast(std::max(MaxSize, 0))) { Trapped = true; } } @@ -152,35 +152,39 @@ class MockEVMBuilder { void stackPush(Operand PushValue) { Stats[CurrentOpcode].StackPushCount++; - RuntimeStack.push_back(PushValue); + CurrentStack.push_back(PushValue); } Operand stackPop() { Stats[CurrentOpcode].StackPopCount++; - ZEN_ASSERT(!RuntimeStack.empty() && "mock runtime stack underflow"); - Operand Top = RuntimeStack.back(); - RuntimeStack.pop_back(); + ZEN_ASSERT(!CurrentStack.empty() && "mock tracked stack underflow"); + Operand Top = CurrentStack.back(); + CurrentStack.pop_back(); return Top; } void stackSet(int32_t IndexFromTop, Operand SetValue) { Stats[CurrentOpcode].StackSetCount++; - size_t Index = RuntimeStack.size() - static_cast(IndexFromTop) - 1; - RuntimeStack[Index] = SetValue; + size_t Index = CurrentStack.size() - static_cast(IndexFromTop) - 1; + CurrentStack[Index] = SetValue; } Operand stackGet(int32_t IndexFromTop) { Stats[CurrentOpcode].StackGetCount++; - size_t Index = RuntimeStack.size() - static_cast(IndexFromTop) - 1; - return RuntimeStack[Index]; + size_t Index = CurrentStack.size() - static_cast(IndexFromTop) - 1; + return CurrentStack[Index]; } void setTrackedStackDepth(uint32_t Depth) { - if (RuntimeStack.size() > Depth) { - RuntimeStack.resize(Depth); + if (CurrentStack.size() > Depth) { + CurrentStack.resize(Depth); } } + void reloadTrackedStackFromInstance() { CurrentStack = RuntimeStack; } + + void syncTrackedStackMetadataToInstance() { RuntimeStack = CurrentStack; } + Operand createStackEntryOperand( COMPILER::EVMValueRange = COMPILER::EVMValueRange::U256) { return Operand(std::make_shared( @@ -194,6 +198,19 @@ class MockEVMBuilder { void spillTrackedStack(const std::vector &TrackedStack) { RuntimeStack = TrackedStack; + CurrentStack = RuntimeStack; + } + + void + spillTrackedStackPreservingPrefix(const std::vector &TrackedStack, + uint32_t PrefixDepth) { + if (RuntimeStack.size() < PrefixDepth) { + RuntimeStack.resize(PrefixDepth); + } + RuntimeStack.resize(PrefixDepth); + RuntimeStack.insert(RuntimeStack.end(), TrackedStack.begin(), + TrackedStack.end()); + CurrentStack = RuntimeStack; } void setCurrentDebugBlockPC(uint64_t) {} @@ -221,8 +238,11 @@ class MockEVMBuilder { template void handleLogWithTopics(Args...) {} - Operand handleCall(Operand, Operand, Operand, Operand, Operand, Operand, - Operand) { + Operand handleCall(Operand, Operand ToAddr, Operand, Operand, Operand, + Operand, Operand) { + LastCallRecipient = ToAddr.resolvedValue(); + HasLastCallRecipient = true; + ++CallCount; return Operand(0); } @@ -335,6 +355,15 @@ class MockEVMBuilder { return RuntimeStack.back().resolvedValue(); } + bool hasLastCallRecipient() const { return HasLastCallRecipient; } + + MockOperand::U256Value lastCallRecipient() const { + ZEN_ASSERT(HasLastCallRecipient && "mock call recipient is missing"); + return LastCallRecipient; + } + + uint32_t callCount() const { return CallCount; } + bool Trapped = false; bool Undefined = false; @@ -343,8 +372,12 @@ class MockEVMBuilder { uint8_t CurrentOpcode = 0xff; std::array Stats = {}; std::vector RuntimeStack; + std::vector CurrentStack; MockOperand::U256Value LastPushValue = {0, 0, 0, 0}; bool HasLastPushValue = false; + MockOperand::U256Value LastCallRecipient = {0, 0, 0, 0}; + bool HasLastCallRecipient = false; + uint32_t CallCount = 0; #undef MOCK_OPERAND_STUB #undef MOCK_VOID_STUB @@ -693,6 +726,133 @@ TEST(EVMJITFrontendVisitorTest, EXPECT_EQ(Builder.topStackValue()[0], 0xaaU); } +TEST(EVMJITFrontendVisitorTest, + LiftedBlockWithHiddenPrefixDoesNotDuplicatePrefixOnMaterialize) { + const std::vector Bytecode = { + 0x60, 0xaa, // PUSH1 0xaa + 0x60, 0xbb, // PUSH1 0xbb + 0x5b, // JUMPDEST + 0x50, // POP + 0x00 // STOP + }; + + const EVMAnalyzer Analyzer = analyzeBytecode(Bytecode); + const auto *EntryBlock = findBlock(Analyzer, 0); + const auto *JumpDestBlock = findBlock(Analyzer, 4); + ASSERT_NE(EntryBlock, nullptr); + ASSERT_NE(JumpDestBlock, nullptr); + EXPECT_TRUE(EntryBlock->CanLiftStack); + EXPECT_TRUE(JumpDestBlock->CanLiftStack); + EXPECT_EQ(JumpDestBlock->ResolvedEntryStackDepth, 2); + EXPECT_EQ(JumpDestBlock->FullEntryStateDepth, 2); + EXPECT_EQ(JumpDestBlock->EntryStackDepth, 1); + EXPECT_EQ(JumpDestBlock->HiddenLiveInPrefixDepth, 1); + + COMPILER::EVMFrontendContext Ctx; + Ctx.setRevision(EVMC_CANCUN); + Ctx.setBytecode(reinterpret_cast(Bytecode.data()), + Bytecode.size()); + + MockEVMBuilder Builder; + COMPILER::EVMByteCodeVisitor Visitor(Builder, &Ctx); + EXPECT_TRUE(Visitor.compile()); + EXPECT_FALSE(Builder.Trapped); + EXPECT_FALSE(Builder.Undefined); + EXPECT_EQ(Builder.runtimeStackDepth(), 1U); + EXPECT_EQ(Builder.topStackValue()[0], 0xaaU); +} + +TEST(EVMJITFrontendVisitorTest, + HiddenPrefixMustSurviveLiftedToLiftedFallthroughTransfer) { + const std::vector Bytecode = { + 0x60, 0xaa, // PUSH1 0xaa + 0x60, 0xbb, // PUSH1 0xbb + 0x5b, // JUMPDEST + 0x5f, // PUSH0 + 0x50, // POP + 0x5b, // JUMPDEST + 0x50, // POP + 0x00 // STOP + }; + + const EVMAnalyzer Analyzer = analyzeBytecode(Bytecode); + const auto *MiddleBlock = findBlock(Analyzer, 4); + const auto *ExitBlock = findBlock(Analyzer, 7); + ASSERT_NE(MiddleBlock, nullptr); + ASSERT_NE(ExitBlock, nullptr); + EXPECT_TRUE(MiddleBlock->CanLiftStack); + EXPECT_TRUE(ExitBlock->CanLiftStack); + EXPECT_EQ(MiddleBlock->ResolvedEntryStackDepth, 2); + EXPECT_EQ(MiddleBlock->EntryStackDepth, 0); + EXPECT_EQ(MiddleBlock->HiddenLiveInPrefixDepth, 2); + EXPECT_EQ(ExitBlock->ResolvedEntryStackDepth, 2); + EXPECT_EQ(ExitBlock->EntryStackDepth, 1); + EXPECT_EQ(ExitBlock->HiddenLiveInPrefixDepth, 1); + + COMPILER::EVMFrontendContext Ctx; + Ctx.setRevision(EVMC_CANCUN); + Ctx.setBytecode(reinterpret_cast(Bytecode.data()), + Bytecode.size()); + + MockEVMBuilder Builder; + COMPILER::EVMByteCodeVisitor Visitor(Builder, &Ctx); + EXPECT_TRUE(Visitor.compile()); + EXPECT_FALSE(Builder.Trapped); + EXPECT_FALSE(Builder.Undefined); + EXPECT_EQ(Builder.runtimeStackDepth(), 1U); + EXPECT_EQ(Builder.topStackValue()[0], 0xaaU); +} + +TEST(EVMJITFrontendVisitorTest, + NonLiftedJumpTargetKeepsCallRecipientFromCommittedEntryStack) { + const std::vector Bytecode = { + 0x60, 0xaa, // PUSH1 0xaa + 0x60, 0xbb, // PUSH1 0xbb + 0x60, 0x00, // PUSH1 0x00 + 0x35, // CALLDATALOAD + 0x60, 0x0f, // PUSH1 target + 0x57, // JUMPI + 0x60, 0xcc, // PUSH1 0xcc + 0x60, 0x0f, // PUSH1 target + 0x56, // JUMP + 0x5b, // JUMPDEST + 0x60, 0x00, // PUSH1 retSize + 0x60, 0x00, // PUSH1 retOffset + 0x60, 0x00, // PUSH1 argsSize + 0x60, 0x00, // PUSH1 argsOffset + 0x60, 0x00, // PUSH1 value + 0x86, // DUP7 + 0x90, // SWAP1 + 0x90, // SWAP1 + 0x60, 0x20, // PUSH1 gas + 0xf1, // CALL + 0x00 // STOP + }; + + const EVMAnalyzer Analyzer = analyzeBytecode(Bytecode); + const auto *TargetBlock = findBlock(Analyzer, 0x0f); + ASSERT_NE(TargetBlock, nullptr); + EXPECT_FALSE(TargetBlock->CanLiftStack); + EXPECT_EQ(TargetBlock->ResolvedEntryStackDepth, -1); + + COMPILER::EVMFrontendContext Ctx; + Ctx.setRevision(EVMC_FRONTIER); + Ctx.setBytecode(reinterpret_cast(Bytecode.data()), + Bytecode.size()); + + MockEVMBuilder Builder; + COMPILER::EVMByteCodeVisitor Visitor(Builder, &Ctx); + EXPECT_TRUE(Visitor.compile()); + EXPECT_FALSE(Builder.Trapped); + EXPECT_FALSE(Builder.Undefined); + ASSERT_EQ(Builder.callCount(), 1U); + ASSERT_TRUE(Builder.hasLastCallRecipient()); + EXPECT_EQ(Builder.lastCallRecipient()[0], 0xbbU); + EXPECT_EQ(Builder.lastCallRecipient()[1], 0U); + EXPECT_EQ(Builder.lastCallRecipient()[2], 0U); + EXPECT_EQ(Builder.lastCallRecipient()[3], 0U); +} + TEST(EVMJITFrontendVisitorTest, UndefinedInstructionAfterProducerDoesNotTriggerStackOverflowTrap) { const std::vector Bytecode = { diff --git a/src/tests/evm_legacy_call_repro_tests.cpp b/src/tests/evm_legacy_call_repro_tests.cpp new file mode 100644 index 000000000..cfa5e86b1 --- /dev/null +++ b/src/tests/evm_legacy_call_repro_tests.cpp @@ -0,0 +1,506 @@ +// Copyright (C) 2026 the DTVM authors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "evm/evm.h" +#include "evm_test_host.hpp" +#include "runtime/runtime.h" +#include "utils/evm.h" +#ifdef ZEN_ENABLE_LIBEVM +#include "vm/dt_evmc_vm.h" +#endif +#include + +using namespace zen; +using namespace zen::evm; +using namespace zen::runtime; + +namespace { + +struct ParsedFixture { + bool IsValid = false; + std::string CaseName; + std::string FixturePath; + evmc_revision Revision = EVMC_FRONTIER; + evmc_tx_context TxContext{}; + evmc_message Message{}; + uint64_t GasLimit = 0; + uint64_t IntrinsicGas = 0; + evmc::bytes Input; + evmc::bytes Bytecode; + std::vector Accounts; + std::string ExpectedStatus; + uint64_t ExpectedTxGas = 0; + uint64_t ExpectedDTVMInterpGas = 0; + uint64_t ExpectedDTVMMultipassGas = 0; + std::optional BlockHash; + std::unordered_map BlockHashes; +}; + +class FixtureHost : public ZenMockedEVMHost { +public: + std::unordered_map BlockHashOverrides; + + evmc::bytes32 get_block_hash(int64_t BlockNumber) const noexcept override { + auto It = BlockHashOverrides.find(BlockNumber); + if (It != BlockHashOverrides.end()) { + return It->second; + } + return ZenMockedEVMHost::get_block_hash(BlockNumber); + } +}; + +evmc_revision parseRevision(const std::string &Revision) { + if (Revision == "EVMC_FRONTIER") + return EVMC_FRONTIER; + if (Revision == "EVMC_TANGERINE_WHISTLE") + return EVMC_TANGERINE_WHISTLE; + if (Revision == "EVMC_SPURIOUS_DRAGON") + return EVMC_SPURIOUS_DRAGON; + if (Revision == "EVMC_BYZANTIUM") + return EVMC_BYZANTIUM; + if (Revision == "EVMC_CONSTANTINOPLE") + return EVMC_CONSTANTINOPLE; + if (Revision == "EVMC_PETERSBURG") + return EVMC_PETERSBURG; + if (Revision == "EVMC_ISTANBUL") + return EVMC_ISTANBUL; + if (Revision == "EVMC_BERLIN") + return EVMC_BERLIN; + if (Revision == "EVMC_LONDON") + return EVMC_LONDON; + if (Revision == "EVMC_PARIS") + return EVMC_PARIS; + if (Revision == "EVMC_SHANGHAI") + return EVMC_SHANGHAI; + if (Revision == "EVMC_CANCUN") + return EVMC_CANCUN; + return EVMC_FRONTIER; +} + +std::filesystem::path getLegacyReproFixtureDir() { + return std::filesystem::path(__FILE__).parent_path() / + std::filesystem::path("../../tests/evm/fixtures/legacy_call_repro"); +} + +ParsedFixture loadFixture(const std::filesystem::path &Path) { + auto failFixture = [&](const std::string &Message) { + ADD_FAILURE() << Message << ": " << Path.string(); + ParsedFixture Fixture; + Fixture.FixturePath = Path.string(); + return Fixture; + }; + auto requireObjectMember = [&](const rapidjson::Value &Object, + const char *Name) -> bool { + return Object.HasMember(Name) && Object[Name].IsObject(); + }; + auto requireStringMember = [&](const rapidjson::Value &Object, + const char *Name) -> bool { + return Object.HasMember(Name) && Object[Name].IsString(); + }; + auto requireUint64Member = [&](const rapidjson::Value &Object, + const char *Name) -> bool { + return Object.HasMember(Name) && Object[Name].IsUint64(); + }; + + std::ifstream File(Path); + if (!File.is_open()) { + return failFixture("failed to open fixture"); + } + + rapidjson::IStreamWrapper ISW(File); + rapidjson::Document Doc; + Doc.ParseStream(ISW); + if (Doc.HasParseError()) { + return failFixture("parse error in fixture"); + } + if (!Doc.IsObject()) { + return failFixture("fixture root must be object"); + } + if (!requireStringMember(Doc, "case_name")) { + return failFixture("fixture.case_name must be a string"); + } + if (!requireStringMember(Doc, "revision")) { + return failFixture("fixture.revision must be a string"); + } + if (!requireObjectMember(Doc, "tx")) { + return failFixture("fixture.tx must be an object"); + } + if (!requireObjectMember(Doc, "env")) { + return failFixture("fixture.env must be an object"); + } + if (!requireObjectMember(Doc, "prestate")) { + return failFixture("fixture.prestate must be an object"); + } + if (!requireObjectMember(Doc, "expected")) { + return failFixture("fixture.expected must be an object"); + } + + ParsedFixture Fixture; + Fixture.FixturePath = Path.string(); + Fixture.CaseName = Doc["case_name"].GetString(); + Fixture.Revision = parseRevision(Doc["revision"].GetString()); + + const auto &Tx = Doc["tx"]; + const auto &Env = Doc["env"]; + const auto &Prestate = Doc["prestate"]; + const auto &Expected = Doc["expected"]; + + if (!requireStringMember(Tx, "from")) { + return failFixture("fixture.tx.from must be a string"); + } + if (!requireStringMember(Tx, "to")) { + return failFixture("fixture.tx.to must be a string"); + } + if (!requireStringMember(Tx, "input")) { + return failFixture("fixture.tx.input must be a string"); + } + if (!requireUint64Member(Tx, "gas_limit")) { + return failFixture("fixture.tx.gas_limit must be a uint64"); + } + if (!requireStringMember(Tx, "gas_price")) { + return failFixture("fixture.tx.gas_price must be a string"); + } + if (!requireStringMember(Tx, "value")) { + return failFixture("fixture.tx.value must be a string"); + } + if (!requireUint64Member(Env, "block_number")) { + return failFixture("fixture.env.block_number must be a uint64"); + } + if (!requireUint64Member(Env, "block_timestamp")) { + return failFixture("fixture.env.block_timestamp must be a uint64"); + } + if (!requireStringMember(Env, "block_coinbase")) { + return failFixture("fixture.env.block_coinbase must be a string"); + } + if (!requireStringMember(Env, "block_prev_randao")) { + return failFixture("fixture.env.block_prev_randao must be a string"); + } + if (!requireUint64Member(Env, "block_gas_limit")) { + return failFixture("fixture.env.block_gas_limit must be a uint64"); + } + if (!requireStringMember(Env, "block_base_fee")) { + return failFixture("fixture.env.block_base_fee must be a string"); + } + if (!requireStringMember(Env, "tx_origin")) { + return failFixture("fixture.env.tx_origin must be a string"); + } + if (!requireStringMember(Expected, "status")) { + return failFixture("fixture.expected.status must be a string"); + } + if (!requireUint64Member(Expected, "tx_gas")) { + return failFixture("fixture.expected.tx_gas must be a uint64"); + } + if (Expected.HasMember("dtvm_interpreter_gas") && + !Expected["dtvm_interpreter_gas"].IsUint64()) { + return failFixture( + "fixture.expected.dtvm_interpreter_gas must be a uint64"); + } + if (Expected.HasMember("dtvm_multipass_gas") && + !Expected["dtvm_multipass_gas"].IsUint64()) { + return failFixture("fixture.expected.dtvm_multipass_gas must be a uint64"); + } + + const std::string From = Tx["from"].GetString(); + const std::string To = Tx["to"].GetString(); + const std::string InputHex = Tx["input"].GetString(); + + Fixture.GasLimit = Tx["gas_limit"].GetUint64(); + Fixture.Input = zen::utils::hexToBytes(InputHex); + + Fixture.TxContext.tx_gas_price = + zen::utils::parseUint256(Tx["gas_price"].GetString()); + Fixture.TxContext.block_number = Env["block_number"].GetUint64(); + Fixture.TxContext.block_timestamp = Env["block_timestamp"].GetUint64(); + Fixture.TxContext.block_coinbase = + zen::utils::parseAddress(Env["block_coinbase"].GetString()); + Fixture.TxContext.block_prev_randao = + zen::utils::parseUint256(Env["block_prev_randao"].GetString()); + Fixture.TxContext.block_gas_limit = Env["block_gas_limit"].GetUint64(); + Fixture.TxContext.block_base_fee = + zen::utils::parseUint256(Env["block_base_fee"].GetString()); + Fixture.TxContext.tx_origin = + zen::utils::parseAddress(Env["tx_origin"].GetString()); + if (Env.HasMember("block_hash") && Env["block_hash"].IsString()) { + Fixture.BlockHash = zen::utils::parseBytes32(Env["block_hash"].GetString()); + } + if (Env.HasMember("block_hashes") && Env["block_hashes"].IsObject()) { + for (auto It = Env["block_hashes"].MemberBegin(); + It != Env["block_hashes"].MemberEnd(); ++It) { + if (!It->value.IsString()) { + return failFixture("fixture.env.block_hashes values must be strings"); + } + int64_t BlockNum = std::stoll(It->name.GetString()); + Fixture.BlockHashes[BlockNum] = + zen::utils::parseBytes32(It->value.GetString()); + } + } + + Fixture.Message = {}; + Fixture.Message.kind = EVMC_CALL; + Fixture.Message.flags = 0u; + Fixture.Message.depth = 0; + Fixture.Message.gas = static_cast(Fixture.GasLimit); + Fixture.Message.recipient = zen::utils::parseAddress(To); + Fixture.Message.sender = zen::utils::parseAddress(From); + Fixture.Message.value = zen::utils::parseUint256(Tx["value"].GetString()); + Fixture.Message.code = nullptr; + Fixture.Message.code_size = 0; + Fixture.Message.input_data = + Fixture.Input.empty() ? nullptr : Fixture.Input.data(); + Fixture.Message.input_size = Fixture.Input.size(); + + for (auto It = Prestate.MemberBegin(); It != Prestate.MemberEnd(); ++It) { + const std::string AddressStr = It->name.GetString(); + const auto &AccountVal = It->value; + if (!AccountVal.IsObject()) { + return failFixture("fixture.prestate entries must be objects"); + } + if (!requireStringMember(AccountVal, "balance")) { + return failFixture("fixture.prestate[*].balance must be a string"); + } + if (!requireUint64Member(AccountVal, "nonce")) { + return failFixture("fixture.prestate[*].nonce must be a uint64"); + } + if (!requireStringMember(AccountVal, "code")) { + return failFixture("fixture.prestate[*].code must be a string"); + } + if (!requireObjectMember(AccountVal, "storage")) { + return failFixture("fixture.prestate[*].storage must be an object"); + } + + ZenMockedEVMHost::AccountInitEntry Entry; + Entry.Address = zen::utils::parseAddress(AddressStr); + Entry.Account.balance = + zen::utils::parseUint256(AccountVal["balance"].GetString()); + Entry.Account.nonce = AccountVal["nonce"].GetUint64(); + Entry.Account.code = zen::utils::hexToBytes(AccountVal["code"].GetString()); + + const auto &Storage = AccountVal["storage"]; + for (auto Sit = Storage.MemberBegin(); Sit != Storage.MemberEnd(); ++Sit) { + if (!Sit->value.IsString()) { + return failFixture( + "fixture.prestate[*].storage values must be strings"); + } + evmc::StorageValue SV{}; + SV.current = zen::utils::parseBytes32(Sit->value.GetString()); + Entry.Account.storage[zen::utils::parseBytes32(Sit->name.GetString())] = + SV; + } + + if (AddressStr == To) { + Fixture.Bytecode = Entry.Account.code; + } + + Fixture.Accounts.push_back(std::move(Entry)); + } + + Fixture.ExpectedStatus = Expected["status"].GetString(); + Fixture.ExpectedTxGas = Expected["tx_gas"].GetUint64(); + Fixture.ExpectedDTVMInterpGas = + Expected.HasMember("dtvm_interpreter_gas") + ? Expected["dtvm_interpreter_gas"].GetUint64() + : Fixture.ExpectedTxGas; + Fixture.ExpectedDTVMMultipassGas = + Expected.HasMember("dtvm_multipass_gas") + ? Expected["dtvm_multipass_gas"].GetUint64() + : Fixture.ExpectedTxGas; + Fixture.IntrinsicGas = zen::utils::computeIntrinsicGas( + Fixture.Revision, EVMC_CALL, Fixture.Message.input_data, + Fixture.Message.input_size); + Fixture.IsValid = true; + + return Fixture; +} + +ZenMockedEVMHost::TransactionExecutionResult +runFixture(const ParsedFixture &Fixture, common::RunMode Mode) { + RuntimeConfig Config; + Config.Format = common::InputFormat::EVM; + Config.Mode = Mode; + Config.EnableEvmGasMetering = true; + + auto Host = std::make_unique(); + Host->loadInitialState(Fixture.TxContext, Fixture.Accounts, true); + if (Fixture.BlockHash.has_value()) { + // Most legacy contracts use BLOCKHASH(block.number-1); mocked host exposes + // one block_hash value for all get_block_hash() queries. + Host->block_hash = *Fixture.BlockHash; + } + Host->BlockHashOverrides = Fixture.BlockHashes; + auto RT = Runtime::newEVMRuntime(Config, Host.get()); + EXPECT_TRUE(RT != nullptr); + Host->setRuntime(RT.get()); + + ZenMockedEVMHost::TransactionExecutionConfig ExecConfig; + ExecConfig.ModuleName = + Fixture.CaseName + "-" + + (Mode == common::RunMode::InterpMode ? "interp" : "multipass"); + ExecConfig.Bytecode = + reinterpret_cast(Fixture.Bytecode.data()); + ExecConfig.BytecodeSize = Fixture.Bytecode.size(); + ExecConfig.Message = Fixture.Message; + ExecConfig.GasLimit = Fixture.GasLimit; + ExecConfig.IntrinsicGas = Fixture.IntrinsicGas; + ExecConfig.Revision = Fixture.Revision; + + return Host->executeTransaction(ExecConfig); +} + +struct VmExecutionResult { + bool Success = false; + evmc_status_code Status = EVMC_INTERNAL_ERROR; + uint64_t GasCharged = 0; +}; + +#ifdef ZEN_ENABLE_LIBEVM +VmExecutionResult runFixtureViaDTVMApi(const ParsedFixture &Fixture, + const char *ModeValue) { + auto Host = std::make_unique(); + Host->loadInitialState(Fixture.TxContext, Fixture.Accounts, true); + if (Fixture.BlockHash.has_value()) { + Host->block_hash = *Fixture.BlockHash; + } + Host->BlockHashOverrides = Fixture.BlockHashes; + RuntimeConfig HostConfig; + HostConfig.Format = common::InputFormat::EVM; + HostConfig.Mode = std::strcmp(ModeValue, "interpreter") == 0 + ? common::RunMode::InterpMode + : common::RunMode::MultipassMode; + HostConfig.EnableEvmGasMetering = true; + auto HostRuntime = Runtime::newEVMRuntime(HostConfig, Host.get()); + EXPECT_TRUE(HostRuntime != nullptr); + Host->setRuntime(HostRuntime.get()); + auto Vm = evmc_create_dtvmapi(); + EXPECT_NE(Vm, nullptr); + if (!Vm) { + return {}; + } + if (Vm->set_option == nullptr) { + ADD_FAILURE() << "dtvmapi VM does not provide set_option"; + Vm->destroy(Vm); + return {}; + } + const auto SetModeResult = Vm->set_option(Vm, "mode", ModeValue); + if (SetModeResult != EVMC_SET_OPTION_SUCCESS) { + ADD_FAILURE() << "failed to set dtvmapi mode to " << ModeValue + << ", result=" << SetModeResult; + Vm->destroy(Vm); + return {}; + } + const auto SetGasMeteringResult = + Vm->set_option(Vm, "enable_gas_metering", "true"); + if (SetGasMeteringResult != EVMC_SET_OPTION_SUCCESS) { + ADD_FAILURE() << "failed to enable dtvmapi gas metering, result=" + << SetGasMeteringResult; + Vm->destroy(Vm); + return {}; + } + + evmc_message Msg = Fixture.Message; + Msg.gas = static_cast(Fixture.GasLimit); + + const auto To = Msg.recipient; + const auto It = Host->accounts.find(To); + if (It == Host->accounts.end()) { + Vm->destroy(Vm); + return {}; + } + const auto &Code = It->second.code; + evmc_result Raw = + Vm->execute(Vm, &evmc::MockedHost::get_interface(), + reinterpret_cast(Host.get()), + Fixture.Revision, &Msg, Code.data(), Code.size()); + + VmExecutionResult Result; + Result.Success = true; + Result.Status = Raw.status_code; + if (Raw.gas_left >= 0) { + Result.GasCharged = Fixture.GasLimit - static_cast(Raw.gas_left); + } + if (Raw.release) { + Raw.release(&Raw); + } + Vm->destroy(Vm); + return Result; +} +#endif + +void assertExpectedStatus(const std::string &ExpectedStatus, + const evmc_status_code ActualStatus) { + if (ExpectedStatus == "success") { + EXPECT_EQ(ActualStatus, EVMC_SUCCESS); + return; + } + if (ExpectedStatus == "revert") { + EXPECT_EQ(ActualStatus, EVMC_REVERT); + return; + } + EXPECT_NE(ActualStatus, EVMC_SUCCESS); +} + +} // namespace + +TEST(EVMLegacyCallReproTest, ExecuteFixturesInInterpreterAndMultipass) { + const auto FixtureDir = getLegacyReproFixtureDir(); + const std::vector> FixtureFiles = { + {"block_254277_tx_0.json", 57956}, + {"block_254297_tx_0.json", 94849}, + }; + + for (const auto &[Name, CanonicalTxGas] : FixtureFiles) { + SCOPED_TRACE(Name); + ParsedFixture Fixture = loadFixture(FixtureDir / Name); + ASSERT_TRUE(Fixture.IsValid); + EXPECT_EQ(Fixture.ExpectedTxGas, CanonicalTxGas); + + { + auto Result = runFixture(Fixture, common::RunMode::InterpMode); + ASSERT_TRUE(Result.Success) << Result.ErrorMessage; + assertExpectedStatus(Fixture.ExpectedStatus, Result.Status); + EXPECT_GT(Result.GasCharged, 0U) + << "fixture=" << Fixture.FixturePath << " mode=interpreter"; + } + +#ifdef ZEN_ENABLE_MULTIPASS_JIT + { + auto Result = runFixture(Fixture, common::RunMode::MultipassMode); + ASSERT_TRUE(Result.Success) << Result.ErrorMessage; + assertExpectedStatus(Fixture.ExpectedStatus, Result.Status); + EXPECT_GT(Result.GasCharged, 0U) + << "fixture=" << Fixture.FixturePath << " mode=multipass"; + } +#endif + } +} + +#ifdef ZEN_ENABLE_LIBEVM +TEST(EVMLegacyCallReproTest, ExecuteFixturesViaDTVMApi) { + const auto FixtureDir = getLegacyReproFixtureDir(); + const std::vector FixtureFiles = {"block_254277_tx_0.json"}; + for (const auto &Name : FixtureFiles) { + SCOPED_TRACE(Name); + ParsedFixture Fixture = loadFixture(FixtureDir / Name); + ASSERT_TRUE(Fixture.IsValid); + auto RTInterp = runFixture(Fixture, common::RunMode::InterpMode); + auto RTMulti = runFixture(Fixture, common::RunMode::MultipassMode); + auto Interp = runFixtureViaDTVMApi(Fixture, "interpreter"); + auto Multi = runFixtureViaDTVMApi(Fixture, "multipass"); + ASSERT_TRUE(Interp.Success); + ASSERT_TRUE(Multi.Success); + EXPECT_EQ(Interp.Status, EVMC_SUCCESS); + EXPECT_EQ(Multi.Status, EVMC_SUCCESS); + EXPECT_EQ(Interp.GasCharged, Multi.GasCharged); + } +} +#endif diff --git a/src/tests/evm_test_host.hpp b/src/tests/evm_test_host.hpp index 06bab37c3..4d3de5e9b 100644 --- a/src/tests/evm_test_host.hpp +++ b/src/tests/evm_test_host.hpp @@ -14,6 +14,7 @@ #include #include +#include using namespace zen; using namespace zen::runtime; @@ -48,6 +49,26 @@ class ZenMockedEVMHost : public evmc::MockedHost { uint64_t CallStipendRefund = 0; // track CALL stipend refunds for prepaid fees bool FeesPrepaidInTx = false; + zen::common::MayBe + loadEVMModuleWithCompileFallback(const std::string &ModName, + const void *Code, size_t CodeSize, + evmc_revision Rev) { + auto ModRet = RT->loadEVMModule(ModName, Code, CodeSize, Rev); + if (ModRet || RT == nullptr || + RT->getConfig().Mode != common::RunMode::MultipassMode || + ModRet.getError().getPhase() != common::ErrorPhase::Compilation) { + return ModRet; + } + + const RuntimeConfig SavedConfig = RT->getConfig(); + RuntimeConfig FallbackConfig = SavedConfig; + FallbackConfig.Mode = common::RunMode::InterpMode; + RT->setConfig(FallbackConfig); + auto FallbackRet = RT->loadEVMModule(ModName, Code, CodeSize, Rev); + RT->setConfig(SavedConfig); + return FallbackRet; + } + public: struct AccountInitEntry { evmc::address Address{}; @@ -308,7 +329,9 @@ class ZenMockedEVMHost : public evmc::MockedHost { ? ("tx_exec_mod_" + std::to_string(Counter)) : (Config.ModuleName + "_" + std::to_string(Counter)); - auto ModRet = RT->loadEVMModule(ModuleName, BytecodePtr, BytecodeSize); + auto ModRet = loadEVMModuleWithCompileFallback(ModuleName, BytecodePtr, + BytecodeSize, + ActiveRevision); if (!ModRet) { Result.ErrorMessage = "Failed to load EVM module: " + ModuleName; return Result; @@ -521,8 +544,8 @@ class ZenMockedEVMHost : public evmc::MockedHost { "_" + std::to_string(Counter); ; - auto ModRet = - RT->loadEVMModule(ModName, ContractCode.data(), ContractCode.size()); + auto ModRet = loadEVMModuleWithCompileFallback( + ModName, ContractCode.data(), ContractCode.size(), Revision); if (!ModRet) { ZEN_LOG_ERROR("Failed to load EVM module: %s", ModName.c_str()); return ParentResult; @@ -703,7 +726,8 @@ class ZenMockedEVMHost : public evmc::MockedHost { InitcodePtr = &STOP_BYTE; InitcodeSize = 1; } - auto ModRet = RT->loadEVMModule(ModName, InitcodePtr, InitcodeSize); + auto ModRet = loadEVMModuleWithCompileFallback(ModName, InitcodePtr, + InitcodeSize, Revision); if (!ModRet) { restoreHostState(StateSnapshot); ZEN_LOG_ERROR("Failed to load EVM module: %s", ModName.c_str()); diff --git a/src/vm/dt_evmc_vm.cpp b/src/vm/dt_evmc_vm.cpp index 17961c8ea..5bc68e0f2 100644 --- a/src/vm/dt_evmc_vm.cpp +++ b/src/vm/dt_evmc_vm.cpp @@ -346,14 +346,27 @@ zen::common::MayBe loadEVMModuleWithRegAllocRetry( evmc_revision Rev, EVMMemorySpecializationProfile MemoryProfile = {}) { auto ModRet = VM->RT->loadEVMModule(ModName, Code, CodeSize, Rev, MemoryProfile); - if (ModRet || !shouldRetryModuleLoadWithFastRA(VM, ModRet.getError())) { + if (ModRet) { return ModRet; } - RuntimeConfig RetryConfig = VM->Config; - RetryConfig.DisableMultipassGreedyRA = true; - ScopedConfig Retry(VM->RT.get(), RetryConfig); - return VM->RT->loadEVMModule(ModName, Code, CodeSize, Rev, MemoryProfile); + const Error &Err = ModRet.getError(); + if (shouldRetryModuleLoadWithFastRA(VM, Err)) { + RuntimeConfig RetryConfig = VM->Config; + RetryConfig.DisableMultipassGreedyRA = true; + ScopedConfig Retry(VM->RT.get(), RetryConfig); + return VM->RT->loadEVMModule(ModName, Code, CodeSize, Rev, MemoryProfile); + } + + if (VM->Config.Mode == RunMode::MultipassMode && + Err.getPhase() == ErrorPhase::Compilation) { + RuntimeConfig FallbackConfig = VM->Config; + FallbackConfig.Mode = RunMode::InterpMode; + ScopedConfig Fallback(VM->RT.get(), FallbackConfig); + return VM->RT->loadEVMModule(ModName, Code, CodeSize, Rev, MemoryProfile); + } + + return ModRet; } EVMModule *loadTransientModule(DTVM *VM, const uint8_t *Code, size_t CodeSize, @@ -379,8 +392,7 @@ EVMModule *findModuleCached(DTVM *VM, const uint8_t *Code, size_t CodeSize, } IsTransient = false; - const EVMMemorySpecializationProfile Profile = - deriveMemorySpecializationProfile(Msg); + const EVMMemorySpecializationProfile Profile = {}; // L0 disabled: pointer comparison is unsafe when callers reuse addresses // for different bytecode (e.g. test frameworks, repeated allocations). @@ -540,6 +552,7 @@ evmc_result executeInterpreterFastPath(DTVM *VM, evmc_message MsgWithCode = *Msg; MsgWithCode.code = reinterpret_cast(Mod->Code); MsgWithCode.code_size = Mod->CodeSize; + TheInst->clearMessageCache(); TheInst->setExeResult(evmc::Result{EVMC_SUCCESS, 0, 0}); TheInst->pushMessage(&MsgWithCode); @@ -631,14 +644,12 @@ evmc_result executeMultipassFastPath(DTVM *VM, const evmc_host_interface *Host, } ModuleGuard ModGuard(VM, Mod, IsTransientMod); -#ifdef ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK // O(1) flag check replaces per-call O(n) EVMAnalyzer scan. // The flag was set once at module creation in EVMModule::newEVMModule(). - if (Mod->ShouldFallbackToInterp) { + if (Mod->ShouldFallbackToInterp || Mod->getJITCode() == nullptr) { return executeInterpreterFastPath(VM, Host, Context, Rev, Msg, Code, CodeSize); } -#endif // ZEN_ENABLE_JIT_PRECOMPILE_FALLBACK // Instance reuse (shared only for cacheable top-level calls) EVMInstance *TheInst = getOrCreateInstance(VM, Mod, Rev, Msg->depth); @@ -650,6 +661,7 @@ evmc_result executeMultipassFastPath(DTVM *VM, const evmc_host_interface *Host, evmc_message MsgWithCode = *Msg; MsgWithCode.code = reinterpret_cast(Mod->Code); MsgWithCode.code_size = Mod->CodeSize; + TheInst->clearMessageCache(); TheInst->setExeResult(evmc::Result{EVMC_SUCCESS, 0, 0}); TheInst->pushMessage(&MsgWithCode); diff --git a/tests/evm/fixtures/legacy_call_repro/README.md b/tests/evm/fixtures/legacy_call_repro/README.md new file mode 100644 index 000000000..900b5341c --- /dev/null +++ b/tests/evm/fixtures/legacy_call_repro/README.md @@ -0,0 +1,24 @@ +# Legacy CALL Repro Fixture + +This directory stores standalone repro fixtures for the historical legacy CALL +gas divergence: + +- `block 254277 tx 0` (accident path) +- `block 254297 tx 0` (guard path) + +Each case file is self-contained and includes: + +- `revision` +- `tx` +- `env` +- `prestate` (touched accounts with nonce/balance/code/storage) +- `expected` (`status` and `tx_gas`) + +Use `tools/extract_legacy_call_repro.sh` to regenerate fixtures from live chain +data. + +For best historical nonce/balance fidelity during extraction, provide: + +- `SILKWORM_STAGED_PIPELINE_BIN` +- `SILKWORM_DATADIR_254277` +- `SILKWORM_DATADIR_254297` diff --git a/tests/evm/fixtures/legacy_call_repro/block_254277_tx_0.json b/tests/evm/fixtures/legacy_call_repro/block_254277_tx_0.json new file mode 100644 index 000000000..4e1c6be6a --- /dev/null +++ b/tests/evm/fixtures/legacy_call_repro/block_254277_tx_0.json @@ -0,0 +1,321 @@ +{ + "case_name": "legacy_call_creation_cost_block_254277_tx0", + "chain_id": 1, + "block_number": 254277, + "tx_index": 0, + "tx_hash": "0x65ee2777a2c5abbd266dbbcb68a02eab73eef913d7106bc9b7cfc2cbabc883d7", + "revision": "EVMC_FRONTIER", + "tx": { + "kind": "call", + "from": "0x26588a9301b0428d95e6fc3a5024fce8bec12d51", + "to": "0xd2826004ee7c528bc50bdcecbd22226c0a754722", + "nonce": 5, + "gas_limit": 90000, + "gas_price": "0xba43b7400", + "value": "0x0", + "input": "0x0047a8033cc6d6ca2ed5044674fd421f44884de8" + }, + "env": { + "block_number": 254277, + "block_timestamp": 1442610103, + "block_coinbase": "0xc8fea4ab769162f6f7eafb8c2bd49734a03c60ef", + "block_prev_randao": "0x27a7afa387a410fd28c4a5a12dd36f8f6bab7d084c0e03059f685887633ccc3f", + "block_gas_limit": 3141592, + "block_base_fee": "0x0", + "tx_origin": "0x26588a9301b0428d95e6fc3a5024fce8bec12d51", + "block_hash": "0xbd689c92697150273a220bb26886e6219f4956297cd562c8a59558005261a3fe", + "block_hashes": { + "254021": "0x6b606f9dfbf71408d93468fd5fef81eadc3d8388373625fca36ec312ed48d812", + "254022": "0xef63f93f81d6f092a0e5fb0a95c5cf8a5af79b1412e32e1390f4cd4b466b81a3", + "254023": "0x006d485928df533d7bcd67627025087ce6051b5096bd90f3bf79075b908da83b", + "254024": "0x84034acc28d729a51790631fdc629f0660dfd6bfa97b684dd84457a28333e7ac", + "254025": "0x4b9840a5bee06967b766eb70d81283750b1bda83ec2db2059113534a0ce8a390", + "254026": "0x7de94c8d05817dc10c5d8995f3b97f5d10f319484d00a463bb4282a187726eff", + "254027": "0xf53d6f0aaa441da0ab33cad63ba340c1d7bd5908aae7486a81ef55eb25c9bd6d", + "254028": "0x32c657874dee824df91078fc8d276c7f5eae04febd58ec8972d24db50b1c3a6a", + "254029": "0x340c29c312654a56f3586b420f7b7d88a27b0f3cbce61ff368801b152e7890a4", + "254030": "0x2f8714a04da62a102d3aa79ea609988b71c918eb2b69d8b0842eafda96c6c6c0", + "254031": "0x20c6d225154aa85cb8784a910720c4e4f4c25161b1132804c5e40ddf10915138", + "254032": "0xf8212ea79ef823b287a27671806b6bc31340011cb639f2bcab96c8be5ebae6eb", + "254033": "0xf92b166b3440a5c6f17891833aff14d35532a609b75481cc00bf552614b199b9", + "254034": "0x845df41f2f45f0aaf89d40635dbbbe57a420edbc804157e1e1bc1cb27b4b0f21", + "254035": "0x82f88255fb93f79a58f6da97a300ac13ad7675d4617ee2e5d1e1d9546187371f", + "254036": "0x19d4bee3ba4e785ed373954d42ebdc1401b0fa80e658272cae0f78676d1c6181", + "254037": "0xf13aa66584e61859a2a536810015ad1ce31e713979246f864bd6a56ac2c14384", + "254038": "0xc5dbe231fef48d73bf16da371ea3d3a690d1d53dd9ee8d3eb7b7ad64ada8507e", + "254039": "0x9a760587d75b097ed737ca9f13335a309537e4ca8f1fe57c46f74e35fd54c852", + "254040": "0x53e66d903606346adafab549df7b797f709a9e319fb206ad32e83caee03e3018", + "254041": "0x02f79072f0f140218d8662a228fe2398efc5d53018ec55a8970aa839bdde6fdb", + "254042": "0xfdb79e7c567e6b130a67658f772c4de9d5d8cc6ac04c724822b196bf32ec23c6", + "254043": "0x37dbf337457485a76c6a33bfce5486e93ffa93ad7565045b1b041b1699e96948", + "254044": "0xfdfae56d5065d5e4e8cbcfe7e5a90d8e55f0d28a591c51eaa99368954871c892", + "254045": "0xc63fd4643a8ff89ee3de47b954afb9c39200081edd260e9e3aa1a4389da536e7", + "254046": "0x7f0a970fa5d1eee358046ea45dab001509e9fd549187dc61a7597175d84a85ad", + "254047": "0x05f0b9477a93a8c2217564d33f2a3a3018ccf64429392edbfc68d42cd2d9f1a0", + "254048": "0xa36ed44786867dfab24ce4327346f68fe068df96ee53880d5fdb7ba8e75cdfad", + "254049": "0x8e1f04e3d61c1942f912efb5b736957011e1e67a640deb20e22f0f18ebb12cbe", + "254050": "0x16733e7cc2cb89bb2297fafb6fa1de9184a7928ea0f8c409c95b0fdb2dde753c", + "254051": "0x8271f05f35ae0ca8bed9999bdfda217bbe7d8f0ce947b25d1c799c5f87dceca6", + "254052": "0xb0f460fcddbb88181790d8dce5e4f448a75201532b64875ca5ca800893692874", + "254053": "0x2b6fbd33dbe310926705547c2d8e86b2531dc769fa40b85626d9c14ad0bbf6bf", + "254054": "0x1dbe8b1e3a08c8c2f0d0c5538ebbdc48894062ca5b1c897da3b42de214041218", + "254055": "0x08b7b87d328a90f11c579b54290a922fde2bf1f82cfbc8ab65c6b8cedc148833", + "254056": "0x313bc0990f23436ab29a21b457d493ed883083cd41a4bf84af99ffd0cf01b32b", + "254057": "0xdea9c24f93c8dbc5b177e80014ba36773f8da79ec3f4788bb4ac2169953164c9", + "254058": "0x7d9f0cc205e88c743413c638c9af8982a6cbe5a9a00d8395944ffd497ecb1499", + "254059": "0x53ecad66ed9c73b543bfb3bed64aa67fae018382d20c62bc51393ddeeebaec3b", + "254060": "0x9d6f638f7fc2e1e8e2ef11736f5fa90b1cf56a71858e3fcaa1ab0337cea85c1a", + "254061": "0x063c1e0e07fcfb6a2160487cf71bab7d1d55255a542c1fab44bf79253ceae66e", + "254062": "0xdd8712ebfec22470880d075c1551656409750ec00c9b9aee016bec08721670c3", + "254063": "0x3ec299832d1f4ae20fe25ef3c74c6eab62bf55a0f86fcd6034d26fdbb3f83274", + "254064": "0x989830679c98e4644b8e3e69f5c9043899815ea7bb59b12c711f4e1119cad05b", + "254065": "0x3bf857eb755e2c8573ea955222ea9551145b2694902c4bca2f268f1b94232115", + "254066": "0xb7b730ab42afddf8952a109de4075784fa0520374a812eb20bb6b3343657ce9e", + "254067": "0x943f56384f8b513b34d2d6bba42d0f7967bbcbf7cfd90ce0d885f7bb2f2c59df", + "254068": "0xa665ed49bae7c637dd0a9ea6307a3d6e32ca12d903a89227d8ef1a618c7f8bc7", + "254069": "0xab5eec730756fa83c3d5f41a881b6e4154711e63955b15b7e5b4fb69198900ff", + "254070": "0x24b47fb1c015d62b49d7b98eb7ad3f80b6068cc7614075582461af3170d458f5", + "254071": "0x98cc0b29ecc275fc5db241ee108d95f257071ba1854af65a8e610b3db50adbf5", + "254072": "0x33f950cbd14defcd2dd35552e93ac9a185aab966419cc9f0d7794084421ca52c", + "254073": "0x8d8e72e7727d4852ba5940d5a58f3391513c1547cdfabbe4fa6e6b4718e89247", + "254074": "0x114e792d680d88c30b0a3dd740cd8343dc5cd45ba6b853d81a0cbf8d2f0e7025", + "254075": "0x6f5017ee317b779e245bcaa63067483e23e22b2cc5100e4cf56345a12413969f", + "254076": "0x3b91bf07eb6389fb4b2a2f7f286622a613c9aa5e9bd7a1c17e8f6e41195011f6", + "254077": "0x2cc03b9a2e8955f92ac9bed34fc94de2effda25d44ae05653f1b427416f4a222", + "254078": "0xf251a73d561b288eeb3ab55690745efa76b613bd009049f921941a8ab53758e6", + "254079": "0xaafc9455cd37ccbde5301f635c320941de9156801aa8ae6377bca5274fc7525f", + "254080": "0xd1ce883bf8ee53362044a7e0c91d3f619f6a72059e900be01794242fb677d9f5", + "254081": "0xa8367082954b1b155683fb5bf1a135ecdba1951f18bad51821be2b2e6fa8ce8a", + "254082": "0x534cb9ce63647ac0fd43b33f4bc2233b5007c4b2683f429520a3e71942bd4419", + "254083": "0xc1a3c8a452389f4f7a68ff82711849ff48f66f96dd5c3deba3a685717a9eb9a7", + "254084": "0x91506cd29e6429dd8b8ffdaf19891c3f38aad50a1c6c28d99d227a2323c5203b", + "254085": "0x524181d85e185f3d25c6af43aaddc5e8332915a78aef247bcd2bddb9a8cd4e85", + "254086": "0x7f8c4b97cf9d933b0822205130e96db07167d687769bf33443e838c6b673b037", + "254087": "0x76c600b266c55c2290b14b0004d7de19177edd938e23789b288e5018ade4e564", + "254088": "0x7cd18e0014c0e1bca4fb68887496f4c3b45359e33f64656fd623709f6bae4696", + "254089": "0x63c0547be41669c834065ced830f8ff61018e8ce63897b0a7e1354282e10c2f7", + "254090": "0xbbef0f77691ed05ae3dbf3dcd4c717c111d2d7082f3b903eded4b1b8455e6e44", + "254091": "0xbe66a276766732d659b580f41a671b55b6d26ec98938e8a02c2b2323c47c5f3f", + "254092": "0x8dd63154a1d7dde59e233d28bb488164d0ee2704b7f940027074ae8e79ff56d2", + "254093": "0x9007eb72fdb0d68bfdb7846d20cda5f276471f229764ad9093bd2aabfac5ee78", + "254094": "0x0d5aa6a035eabe65a3d58c99789c2effb45da56bce1eb132dcd79873c24c02d9", + "254095": "0x83a9bf0fb5f8e89ecc9e8abfec96c90deca84b495b17b376a7d44d038a0e1745", + "254096": "0x0ee606e65bd974fb3f2ba89a386a4748d2a3afc24f897aa8919fcaedf774bb4d", + "254097": "0x744b1b39926a3650f01d530a2700b2d00fb13f1cb65f8dd8c1780a4392b82588", + "254098": "0xf09df5de4cbeddefa2df18844b94420ed206fc340549f4f97b0a02134c21f1c7", + "254099": "0x1776f448fcf675cc23d1e2c22b6233856a8ef9a92f59e014f8c53750be8a0717", + "254100": "0x55c54192772dfa7ca2cedcdbb8c4441b41aeb4ff08735150664ceb63ccf752d3", + "254101": "0x30de5bf9f43dbddba65a57afea6362bbdadbcc77d612ca97d8acf469fb7759eb", + "254102": "0xc54591701f743e6a20f42548ba9ebb826c7cc6d869d373baa55db60f04963235", + "254103": "0x52df87cfc24d9a7d65edbfa8da032796557875072f6de3fcccf4fb92c82534a9", + "254104": "0x3cc91fe60b9ef3346a9b814b1c92d45f9ee545fa2d28571f67632b33a42e63ff", + "254105": "0x1aa314a634503a4792536cdd0c1b0da211f370e73b398efdecbc34795eecb579", + "254106": "0xbf62a79aa6c5f150ecadfafdc13358248c9d0891cb6d5b31079261d3316f33d1", + "254107": "0x850219a80ced9b65a074ace745a7da75afdc2ccc1c3cae08ff879b000ddd3600", + "254108": "0xa908f76b9e6a176929a8a39a2863aad942839240208e1fed56a6841a415ab7a1", + "254109": "0x180df169cbc48a2201a4987307464026bfd9363958c24f2d118044309b062391", + "254110": "0xa7f106ac5e877ce7964c98c3c47ca55c61930b7f95f9ed5b73d4fa8048a483e6", + "254111": "0x5557c43ab21ad3393466cce7362b64a5b512461fbd993ce8501248d6ad7c5271", + "254112": "0x09d90edbd8d818158c4fac56d4525af9d12ef163a05d121d95aa3dacc1446f19", + "254113": "0x288f48d10b02e1475d8b954fb4d162d436d9ffe33d0c0ad43bcce0223893ee88", + "254114": "0x1d555c73c74b78fe79009bc0b665e1a9dcb521d1c672bb6702223997732c31da", + "254115": "0xb4283e432256060452e6c4888d22f5c22772df4a30f8414e33346efe7deb56e6", + "254116": "0xb5f789868d8b48271ae64af8ac9a30415286cd3b8bd55fe691e282973e3115c6", + "254117": "0x2ace1904308d82470b2a8f0ca7793b9a096c3bcb4b12cae96ad02b0d0b91f330", + "254118": "0x9fffb3efbda6ef6f04f8cc65a945b3a6290d84dd4a5e82f2355bc79cedf2b94b", + "254119": "0x804da422519ab9ecb6dbb25cbcc905ce2bbfbc6a4ec6bb7f683a030be70bda5d", + "254120": "0x0e3878eb19d22d67a397474f28d22b77448d54b56af89cd6d69de9744262700d", + "254121": "0x1f05e70603c2ddfc8bab791ab78925a754d244c6185daaa008714802b0ca8f65", + "254122": "0x8b89bd4a5a2bf5da8599f0aaf56d5473e29da19c6af16bdb804c1b41b450ac4c", + "254123": "0x937ae77b4aa1f8789b5fd4236dccaa29174083db1ed40fb12f8d985da6ea9d88", + "254124": "0x08292a245bd2443f67b377277c6ff392840114bb474bdfff094a92b810daa8ee", + "254125": "0x60f49742aaf99eb21b90c9f5d87f426b8f083c59a30eb43d34e46fb1d3bd9940", + "254126": "0x06d9058f44b41ba0609f27de303c2e08612b108d5516f09ea97d12eab3cc5188", + "254127": "0xc49bfe83cb9abcbe832fe6f1c0e38c2043fe14fd68c6de86588a58b5f2a6c782", + "254128": "0x28869b77652ad95fb99ae0faf8e1cf14101294d1d5e1262487e975c90b3bce2a", + "254129": "0x8c218127d38ca1d58f0951b222bd18042af63c243d6866196c591367b8a8d37d", + "254130": "0xbcca2687646f2c1937b5743fa9144909f10f9712dceb374dba808f6bc8021f01", + "254131": "0x772b6900ff72c950472d927819198e4a1311f79102fb2fd4118fc1b804a5f17f", + "254132": "0xd210774438ab168e8f95a742b1b1573662572d9ba5fcacd3927d84d8ecaa55e7", + "254133": "0x6ef2a18bd2158fa61e0dfe9917425c6af0cbd569ca643849372a9e3460c4f6ad", + "254134": "0x6dd8c5fcb753e0094549461f592e47c56d09ba1d695ac735702b38cd7edda159", + "254135": "0x3c8920f9615906ec54b6570901394dbffe4c7910136e23d90eb2a879d3805189", + "254136": "0x880508600187588233da82124c03674bc82584b664e20b28afea9317d7a4c015", + "254137": "0x39b4124ad203f110d1ab3097e5d8fbe22be28aec3c7fb0fd5c83f6c634a20f20", + "254138": "0x4736fa52d7ce830d0cf765df167d3c4d49738e697bb2f244551ae34f558e062d", + "254139": "0x1b0f57838af0731cffb9ed7676c52e33a2be649cf6f91410ef255bc990209254", + "254140": "0x676d6df4c69d2110677d0002f6ff8b2ddb567da3ee60b0a6ee87d00d3bf75379", + "254141": "0x333c4c6f2b12943aa17776ba72a566095c8f9678efac29ba7a7324c325faf176", + "254142": "0x4b62e6bf9f4a2d901808553635f69d1d982cf386a71637b529980f50f9df4f6b", + "254143": "0x47d20fa4f2e43608edf69862bf0d2c04dec612593235a39cb098daac65829e30", + "254144": "0x958862f0eb9d2055e3bbc50c4b6bc5464c279f7c8ecd452cc92dc1e921b0f908", + "254145": "0xb458e4626ad33f37c825a5806af56d9b2bd9cf66ab87957435675391ef521d6f", + "254146": "0x15e76ced896d1ed56ddcff68e71b2fb1b28f9dcaaa2378bcfd202ac1886e7efb", + "254147": "0x61ae19a83e6f293ad4af89ff75f6327c5047aef8b62279651e8e1c6bf1ee0593", + "254148": "0xbd20487dd578f1abc90998da5b8139c8fe841f9fc381c8024b7ade5bf13e6f28", + "254149": "0x229bec8d047268d2b130aa726f87d6207dbe2f0eddccb4333ceabb2aea50e93a", + "254150": "0x847e018de0560f4718293ef4ca8a952957afb57a3a7ccd9200ba32f3830e4fd3", + "254151": "0x6cf9eed7505fed3c6a35c58a081bf89b1a0a4eec02fe193e671998d3c0589d89", + "254152": "0xe6c147e1d9107aacac78dac53a28dccddaacf80ff177f9ed3384431c8122a1e4", + "254153": "0xb72524d60d1a8da9fafe1c8f9a5cf38e2437fd038d40ad085a9df5bf930e0190", + "254154": "0x0f43d3d224579f144054434846859a26e09ca78cae83983d5ef59a701a805761", + "254155": "0xa3f8ca2d78caeefedce060f70a60676da44494667783809eb4e6f9ddcab5c9f5", + "254156": "0x5f90c7d14d0ad23f1b26c6c664d474fe1d6e510cd8d0efb9aff3d2a1365d9a1c", + "254157": "0x5b9c22aaba0785ccd1fed57fe6253a9bab522bbb9a21481920358283a2fa38ed", + "254158": "0x3ce3be5de4e83d2938ccff0f30816ae1963bb12f68e9b97f26aac7e3a16bd79a", + "254159": "0xfb9a0a14a48820af9c4146d32f0aa54691d0fe09e0d92d75613893a99917e1d5", + "254160": "0xdba25253e5b9ca6e7710c81cc39a48c25cd98eb131377fe4be983904c2afa1fe", + "254161": "0xf52f93c675faffba47d2ece16440661015a1d32532b3a930dddcd4c8d58bdee6", + "254162": "0x6d452b1355e73fd26ae329a92e7169c641d667d14a6fa88223627c2067c11e12", + "254163": "0x7917843f7baca0e311511b83f91bc86bdb8c00638e17cf05d2c7d90bb09645ac", + "254164": "0x229b612b7935f34e11ca5a354f21410a3d3af2ee7e92ea93e3464cc0bb6dc78f", + "254165": "0x6819854a98d2c1e0ceb962aedaee0b1ab2570c6006f100a9b2e222d60aaf7d49", + "254166": "0x2ac7a9a449f2e5054c586fb57f6a1372397d5ce999ffb41d1b9a77ad15ea3414", + "254167": "0x755ab4e575593ebe9035396dd44ff5662f066922bfc31f390e126ddca2f476bf", + "254168": "0xefc4866ef8061c2d5d23520e13f2b835c85c0af93ccbb859c2b131fd6e289976", + "254169": "0x4ec88e9967413f18a0e5b3608f3c02c05bd729089c3ec3a4664e7d424ce04e50", + "254170": "0xcc9f8a148decb545d8cf0f40c0706f8e7104620c4c546addc1a218aa1f81aa90", + "254171": "0xec30a5cf49bd9ff32433d40276138be2cea4c391b1df9e277068f69ae73652bd", + "254172": "0x62b523f3cdf40547fca3cb7eb91815e6df9b830574ffd9d1607d4abb6f9f3a73", + "254173": "0xef7424d2c7fd2a9bca7c0d4c55503905c147b2b70c9bcad57db4989c46b2089d", + "254174": "0xfd9e2fa11e4b9106860894df001f7394df04d79e84a1f10ef09493c13c1c04f9", + "254175": "0x4114a9f78469ef4bee3d3af1ad714dd57853e810a13162fd0f1fae6ddd54d3ee", + "254176": "0x2aab88ba9d0f2a5745416daf9417e044b42ff0d9f853323ab2d07a09b5c67013", + "254177": "0x88eacb8a30b0ce70b12716acd86bd2241841959b7bfaba7ca522e0ee7c167e01", + "254178": "0xb61b699d55187fbd4125339f84734c7956a7713c3ba11688f766e1539b186374", + "254179": "0x10fed5c2037b71bd48943f60cbb19354fadbf9a0c1a167e5bc1688acf5eb5e3f", + "254180": "0x980a743d8fc1c14f0dfe3127979f9f8e5853797603756521e1ab7b9e3ad27c2a", + "254181": "0xc7fb787f2f23a48d5d5ea1e595385f0dd1d5159b338775516b2c1d41c16ec761", + "254182": "0xbef8253c05530905f6983414f7cd025a39217bbfe89b631f1c703e5b1b71cc84", + "254183": "0x302659ade583955e3bad7e63bedb7fa18cd356de2b3d1a169ec315d6e5a3d0ad", + "254184": "0xff8cd55b91b961218a8f5952026179d0bf0570618e36ed4c427bf2d60fe317a3", + "254185": "0x30903d2c9d4b8e937b3a572ba2a209f360598b1ccdb4817211a2df0571ca159d", + "254186": "0xcc75fe2fce32a781d72072abea99a2b73aa0d7fc8f46b29143582b90b92a8a90", + "254187": "0xcbfc65750b3c21d96698718589765a34863094955eaa4566755895da95fc9b9c", + "254188": "0x1712c42d31098308d6e1b53205ae12b9a3b300f267847932afcdd85484058931", + "254189": "0x27a0e9b125d0a09bfa76f48210a5b9d7fc58a02087cf23cdf6b28e8d93b566fa", + "254190": "0x2a8f25eacab2717a50ca43d8b31bed5bbd297ac8879b67d6b2a8c4b559281460", + "254191": "0xeb67c72a0bfd579c6891d5b2d3ad8b6d68dfc519eb59efbc744b300888d3e3a2", + "254192": "0x04aa9d55b48e28fc457ae2393e8c11d294ad70907156566f853406d3da27b386", + "254193": "0x4502a753bb5a68736ab2f1acccff5518430df5e63a0170dbad046326358802dd", + "254194": "0x99bd5cb9bb482243edd3f914a978dae70aa6af53997238d0fbcc4428c52d9c08", + "254195": "0xa67b0130b7b1394b1ed6d898a22f3ab071d5c70ddf2f290384f70530234c9c99", + "254196": "0x3fa85b2ecf6127672cb04e9a1f599555804f70feea8dba09e6601a091f378880", + "254197": "0xfb67e7ebc461c38a8f5379b083d6eb59c94cd15c23060e6eb7eb47c71fa0abe9", + "254198": "0x6457550e55f24ea4929445c6135cee9d87ac8944bbf50fbd93a8d893619fd8bf", + "254199": "0xda3c364b620188a8f5cdf70da86a541d022e6249109b06073b7a336108b34fd7", + "254200": "0x05c63b07077eafd60a02723303776d6a57dc45605463f3645ad7ab4c1989291b", + "254201": "0x91905289af8ce384d5afa6c20cd6557a343ccdac9c9c1c5d13820eb2bdaef1fa", + "254202": "0x255cac9e079cc14cf0d55604329e239720557afd1e0f986e45418c20d85bdb8b", + "254203": "0xaf859bf5ad02d19d1d4c11469173b6d64040bbfd229cd2bfc840a7a486b5ee09", + "254204": "0x0bb505d20425e2f845ed9c7eeabdd132f9fd7c1607fd2d42389d1ec2534662cb", + "254205": "0x0d8435a9cff7fb00cf803d666fb4be7b07a919130084d7d14555190f4388d92f", + "254206": "0x04261fcfcc1ee48197a2ace46fc9cbb158f41a363f993cc566bb87c101150c22", + "254207": "0xb4cd463330d7dd596790ec29e6ba28633ba9563157007fd0e152c54a13f94bb9", + "254208": "0xcf6c11891d79ab5ce1a8735c6fa2554dce8da8e0a0dfa9a9b563034f62972ba6", + "254209": "0x190ec8c8a7c587bdbfbf35f4f975ca6ddb89b41a2b5e7512dbed30b9f0923a0d", + "254210": "0x027c29a9d65708a4f4b678d15ac543378f8f78897a28f30ce455b1edd1bcb9a6", + "254211": "0x595fd8392ecd427501d0d7be945a56fc73a65818af5f606c92b995aa7b41613d", + "254212": "0xcc92045e7ec1cbc57968a140faa7482dc785a45f56405dc36ae6e1d05e1179dd", + "254213": "0x529a0dfd6602381c238ba7d4d8f0107fd5ce74942eb0ec77ba0b37659191d94a", + "254214": "0xef137cef6df1471072e5071b1f73c6611cb73f476cb8123425529abb826ccabf", + "254215": "0x7aac3b4b88be2c680e29a6cfdb7091aa7e3af35e41a9ab755beac435ea64b935", + "254216": "0xe7e368454d0e8ed744d808bc69052c72a75f3819a3cf75b921d7d0ab95b5cc29", + "254217": "0x937f0f1718cfd17e505ce36f891d592070afa2049e2f897e8af87b69eb56f342", + "254218": "0x84bb042e765de65a689a3d58202d639a64850bd6aefbd0d1e90058196f874517", + "254219": "0xd27618753a76d0fb7d09f9e09ffdddf946a0dcb4de0cd79a18fe9c538e23b3a0", + "254220": "0x29c8f6967930cf862029461db2cb0534e521c6291a6f0d23a74befb714b5ebf6", + "254221": "0xda35acba1faf4e445c280442e18bdaea359b3c253b348359b9968c98ae53c986", + "254222": "0xc6fc8356eb823fe131aeba3736804b68f964a7a579c5f324e3a4c4b639a34619", + "254223": "0xe4a3c8107f916ccdaaf772e0d882478561d0cd5dd496c70a0d5a4240c6e35115", + "254224": "0x03b97dc801f4aef71eaf06fa39c12dcdaf00295b24bf843af3584a851db158af", + "254225": "0x7e90ef2ead2ab921693b89483d3d01f64b69ee326668a47559b271aea9034470", + "254226": "0xe73be9b7be4d6133997129b7855b1e6049072aca21493d10d7015536a55b6202", + "254227": "0x181269790ac7a09a221aeaf26092a5a96428dffce726c51829914e1d8aa6cffb", + "254228": "0xa990c6af9bb4823b24df3b9b476e96ae986514196b7188db1ad8675c1bad133a", + "254229": "0x114f2aab33949e4ab96961ad8dd1015b1045a46a237b6bd8c5db37876479a490", + "254230": "0xf80976caa7ef1bdeec75cdf2993d440a814ac56d3267b3d80d7a0c6dde51306f", + "254231": "0x5136ee969c78b9743a281c3e1b64f70566dde0059b1a8dc413f6cf282b75419c", + "254232": "0x226699482dcf407e15529b166b5da191d3c938b0e22209bc97fca6117e011a94", + "254233": "0xb19485e02d3fcefecdbf632d69e12c6fa68b12ae1bd7ffaad4f34a63e2062993", + "254234": "0xb45060f5854e946dfd0407ddd12c056fd7ab748e8074a318af6d593f47d87196", + "254235": "0xe43516b2e1c9f50fcfe48ef120a43f9a5f308bf3a03eb93e5b2b02de575fdd85", + "254236": "0x62fe2c801ca3ea11f4efc769c903f1850feae060d166b2780273e0de36ef11f6", + "254237": "0xaa97396ceede3d5e6a6194e9bdea9e51157268487ba3ad87a01a7e4523ab032c", + "254238": "0xe677f58f7ff6cb71ea85874e3479ad6aca4b1c5ba03ffcd6fd768028ac973fc8", + "254239": "0x191ca284681272e0d99ddc547e2f84299fd8760e9feaafc274da532751596360", + "254240": "0x2db5c4aaeda66a2c6ce36638c31414cb48d545fbbf055275fe00b944deab5ff1", + "254241": "0x30b2ae28d5b62e11f89ec7b518d306d840bfae1356e1343f4e513f4288a80ed7", + "254242": "0xeed9c4af27855c7e6c3a9eb7a8cdbdb99f77e2ea8ff1c60472fb6dc812f21295", + "254243": "0xcbd113360afec5506f07fe0158595cb89de5915b7a04f481334423d33ac04f77", + "254244": "0xec89a841abc25ed83bce8e4dece37615e73a17cc68e697f2aab0538967e6dee7", + "254245": "0x8750998f251188aa782ad88a269613136e13163b808e6d86c175fa12fe89e198", + "254246": "0x3949efbd1e67390cc9b05e0bd9b3579d3c4e52599aeb6433f56c15e7ffa5bde2", + "254247": "0x63958f93098b82050dd936e9dceb1579e045de927a32f481f10bfc82153e82d9", + "254248": "0x33a5447294234e86d97b706d8b5c32ff535334f9c5fde6a832cb3ed9e7e70a53", + "254249": "0xe8982505a9f5b1921a16d172c3291918be118beb0474db3d76aff57ac61f2d8c", + "254250": "0x9a4b4fb0c5879cd71153e8d3755b6e37cebdf8efea59e1f7503cdabefbaab419", + "254251": "0x48d48c37c0cdf11fd592f001c3535fffec7000d79ad3711bc0542e17607b6f59", + "254252": "0x2c2d53a3dbce052399db3942f353caf73e4d69e73955f4ca26506337711e050b", + "254253": "0xa71e2795ccbe6a71123924fd2be6c1ae26dd88d80edae6023eff5f8854238b7f", + "254254": "0xd90d7abd127973be24b285fefb7b6f692df827cfaae6f6893f4afc8556a00c8f", + "254255": "0xf840ce12169ec7c3a882aa78ede2d91852cc01ae2e27076535c4d533a049a6e5", + "254256": "0xa5f37f58ba4d5387e23ecd0141ad8c30cdc91e222b232898b8b18bb2d2862993", + "254257": "0x6a41907f66d6c6dd33372c77bdd2fb527da8fd24137a38abbc5ab6424d773d14", + "254258": "0x98af953ab95f84af13f977b57bf84170f39128bfc30b17748e0b71df6990e734", + "254259": "0x856764bc184093cdf216c51c1a669f0ff5f384b5f55c88a50ddd99a46f112f33", + "254260": "0x614d1df124e3145027afdb090521100fb098263d796f25ef7f4aa2191f90386e", + "254261": "0xe4dcc9156ea3b471a4cda9d95a889d51c10bf32b1c6f3e0a41c07ea60473c296", + "254262": "0x1b1fcba870981e93855be5ad680f3414728309d23d7f35b280bf3d536055c3fc", + "254263": "0x5b954f3671a4306ce79d7bc64cc2cf02a5cbbf50b8aab14d1f6c7a66e14ed23d", + "254264": "0xf71475425852f270d97a7a7ab721e60e9d8e6731efef8ab90758c7d881dbe686", + "254265": "0x9cf6644fec85eaf4370038fee06efa648e169572376e69dd5eeee94081f65a31", + "254266": "0xee8923a3c19bb4bedc077c8e094dc0991a57fd308589a445af3029c6a8b70248", + "254267": "0x034a4812250f89d06b4a4eeddac68d0929cf9abf4648e361aa93e7ebadd32a3f", + "254268": "0x0cfebc0876c679192cdb0bf25c205a6a046db6a8f32cc02ade52c33cc58e1a5a", + "254269": "0x732228f5ccf4c52fdc0cd8385675425bfb39fafcf6a19a3734d6c872d4e90e7c", + "254270": "0x132a64af39d99da47831adf77e0a883fed92dd6cd33b863e6dbdd3409e5c11a2", + "254271": "0x68c46dc8c2f3aee2ec1999162736465965f85d4af8ed4d439dd1ee79660d125b", + "254272": "0x62bb256436b09803a694d66dd57a86244c2a9b3d9f61471bac8116b87e0440c3", + "254273": "0x47db9a800632dcef9c26cd3a6ace949c21808007040d11fce0cc40eb83b5e794", + "254274": "0xcc1f12a4013d122ebfb397f3c8c1102542baaf71d1e83ea691b4186c2640aca3", + "254275": "0xce3f1d03b7b8ba062f87493c470a6294326481f65e8cbe531a11923afb411261", + "254276": "0xbd689c92697150273a220bb26886e6219f4956297cd562c8a59558005261a3fe" + } + }, + "prestate": { + "0x26588a9301b0428d95e6fc3a5024fce8bec12d51": { + "balance": "0x0000000000000000000000000000000000000000000000000dcc32d31a229800", + "nonce": 5, + "code": "0x", + "storage": {} + }, + "0xc8fea4ab769162f6f7eafb8c2bd49734a03c60ef": { + "balance": "0x00000000000000000000000000000000000000000000000b1daeec25c1f29a18", + "nonce": 0, + "code": "0x", + "storage": {} + }, + "0xd2826004ee7c528bc50bdcecbd22226c0a754722": { + "balance": "0x0000000000000000000000000000000000000000000000000000000000000010", + "nonce": 0, + "code": "0x606060405236156100a35760e060020a6000350463187c5903811461010d5780631bccca141461013d57806327e235e31461015e57806329f8df0d14610176578063444bdb1b1461017f57806351870150146101c857806367c18aa1146102db5780636d4ce63c1461038f5780636e723e24146103bb5780636f7bc9be146103c457806371ad7221146103dc578063a32da9d1146103fc578063e8b5e51f1461041d575b6104796305f5e0ff606090815260009081908190819081907f909c57d5c6ac08245cf2a6de3900e2b868513fa59099b92b27d8db823d92df9c90602090a17326588a9301b0428d95e6fc3a5024fce8bec12d51600160a060020a0333161461047b575b5050505050565b610479600160a060020a0333166000908152600b6020526040812054819081908190811415610793575b50505050565b610545600435600681600581101561000257500154600160a060020a031681565b6103a960043560056020526000908152604090205481565b6103a9600c5481565b6103a96000808080805b600c548310156108f1576005818085838110156100025754600160a060020a031690525060208190526040822054029093019260019290920191610189565b600480359081013560208102608081810160405260608381526103a99460249491939085019282918490808284375050604080518735600481013560208181028481018201909552818452989960449993985091909101955093508392508501908490808284375050604080519635600481013560208181028a81018201909452818a529798606498909750602492909201955093508392508501908490808284375050604080519635600481013560208181028a81018201909452818a5297986084989097506024929092019550935083925085019084908082843750949535945050505050600160a060020a0333166000908152600560205260408120548190819081908190111561071c57610710565b610479600435602435600160a060020a038216600090815260056020526040812080549082905590808311156103345783600160a060020a0316600083600502604051809050600060405180830381858888f150505050505b5b600c5481101561013757600160a060020a03841660008260058110156100025754600160a060020a031690911415905061038757600080826005811015610002578054600160a060020a031916905550505b600101610335565b33600160a060020a03166000908152600560205260409020545b60408051918252519081900360200190f35b6103a9600d5481565b6103a9600435600b6020526000908152604090205481565b600435600160a060020a03166000908152600560205260409020546103a9565b610545600435600081600581101561000257505054600160a060020a031681565b610479600160a060020a0333166000908152600b6020526040812054141561046c57600d543390600690600581101561000257018054600160a060020a0319169091179055600d805460010190555b6040600020805434019055565b005b5b60148410156104b457600494909402938084368110156100025760f860020a903581900481020490950194506001939093019261047c565b600160a060020a0385168082526005602081905260408320805490849055879550935082908402606082818181858883f150505050505b600c5481101561010657600160a060020a03831660008260058110156100025754600160a060020a031690911415905061053d57600080826005811015610002578054600160a060020a031916905550505b6001016104eb565b600160a060020a03166060908152602090f35b73393519c01e80b188d326d461e4639bc0e3f62af0905080600160a060020a031663a0a1cddb86612a3001338c8c8c8c6040518760e060020a0281526004018087815260200186600160a060020a03168152602001806020018060200180602001806020018581038552898181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038452888181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038352878181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038252868181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050019a50505050505050505050506000604051808303816000876161da5a03f11561000257505050346005600050600033600160a060020a0316815260200190815260200160002060005081905550336000600050600c600050546005811015610002578054600160a060020a03191690921790915550600c805460010190555b50505095945050505050565b5b600c54821015610757576005818084838110156100025754600160a060020a0316905250604082205402909201916001919091019061071d565b346005028330600160a060020a03163103101561055857604051600160a060020a033316908290349082818181858883f1935050505050610710565b5b600c548310156107d3576005818085838110156100025754600160a060020a031690525060208190526040822054029093019260019290920191610794565b30600160a060020a0316318411156107ea57610137565b9150805b600d5483101561082c57600b816006856005811015610002570154600160a060020a03169052602052604081205490910190600192909201916107ee565b6040812054600160a060020a03338116808452600b602052309091163186900391849004919091029182606082818181858883f19350505050506000600b600050600033600160a060020a03168152602001908152602001600020600050819055506000925082505b600d5483101561013757600160a060020a0333166006846005811015610002570154600160a060020a031614156108e5576000600684600581101561000257018054600160a060020a0319169055505b60019290920191610895565b9150805b600d5483101561093457600b816006856005811015610002570154600160a060020a0316905260205260408120549190910190600192909201916108f5565b5030600160a060020a031631929092039091046064029291505056", + "storage": { + "0x000000000000000000000000000000000000000000000000000000000000000c": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x99395a8467d3a9fabcb16adb3a79e4611e53703cf97b4afad310d43faffd16ad": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + } + }, + "expected": { + "status": "success", + "tx_gas": 57956 + }, + "meta": { + "source": "rpc+trace_replayBlockTransactions", + "rpc_url": "https://ethereum.publicnode.com", + "trace_includes": [ + "stateDiff", + "trace" + ] + } +} diff --git a/tests/evm/fixtures/legacy_call_repro/block_254297_tx_0.json b/tests/evm/fixtures/legacy_call_repro/block_254297_tx_0.json new file mode 100644 index 000000000..efb18992d --- /dev/null +++ b/tests/evm/fixtures/legacy_call_repro/block_254297_tx_0.json @@ -0,0 +1,328 @@ +{ + "case_name": "legacy_guard_block_254297_tx0", + "chain_id": 1, + "block_number": 254297, + "tx_index": 0, + "tx_hash": "0x342b28ad3b4a91f747274a1d241c5978a2ccd50f0124eb1423a4dd55783eaa99", + "revision": "EVMC_FRONTIER", + "tx": { + "kind": "call", + "from": "0x0047a8033cc6d6ca2ed5044674fd421f44884de8", + "to": "0x1430236a73a97654bfb6851eb7e8facdfbe2cdb5", + "nonce": 216, + "gas_limit": 1800000, + "gas_price": "0xba43b7400", + "value": "0x1", + "input": "0x5187015000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015b576f6c6672616d5d200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012774656d706572617475726520696e204c6f6e646f6e2720000000000000000000000000000000000000000000000000000000000000000000000000000000013e2035000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + }, + "env": { + "block_number": 254297, + "block_timestamp": 1442610391, + "block_coinbase": "0x1dcb8d1f0fcc8cbc8c2d76528e877f915e299fbe", + "block_prev_randao": "0x988c4d215f1545d08d79d42da2f7601d6477ccec568e6d3f4fe9ef28ac9d8c8a", + "block_gas_limit": 3141592, + "block_base_fee": "0x0", + "tx_origin": "0x0047a8033cc6d6ca2ed5044674fd421f44884de8", + "block_hash": "0xf3a1a8db998fcd113063fdf801cae8aa5a450c12d3c72eda61eb56b354bc18cf", + "block_hashes": { + "254041": "0x02f79072f0f140218d8662a228fe2398efc5d53018ec55a8970aa839bdde6fdb", + "254042": "0xfdb79e7c567e6b130a67658f772c4de9d5d8cc6ac04c724822b196bf32ec23c6", + "254043": "0x37dbf337457485a76c6a33bfce5486e93ffa93ad7565045b1b041b1699e96948", + "254044": "0xfdfae56d5065d5e4e8cbcfe7e5a90d8e55f0d28a591c51eaa99368954871c892", + "254045": "0xc63fd4643a8ff89ee3de47b954afb9c39200081edd260e9e3aa1a4389da536e7", + "254046": "0x7f0a970fa5d1eee358046ea45dab001509e9fd549187dc61a7597175d84a85ad", + "254047": "0x05f0b9477a93a8c2217564d33f2a3a3018ccf64429392edbfc68d42cd2d9f1a0", + "254048": "0xa36ed44786867dfab24ce4327346f68fe068df96ee53880d5fdb7ba8e75cdfad", + "254049": "0x8e1f04e3d61c1942f912efb5b736957011e1e67a640deb20e22f0f18ebb12cbe", + "254050": "0x16733e7cc2cb89bb2297fafb6fa1de9184a7928ea0f8c409c95b0fdb2dde753c", + "254051": "0x8271f05f35ae0ca8bed9999bdfda217bbe7d8f0ce947b25d1c799c5f87dceca6", + "254052": "0xb0f460fcddbb88181790d8dce5e4f448a75201532b64875ca5ca800893692874", + "254053": "0x2b6fbd33dbe310926705547c2d8e86b2531dc769fa40b85626d9c14ad0bbf6bf", + "254054": "0x1dbe8b1e3a08c8c2f0d0c5538ebbdc48894062ca5b1c897da3b42de214041218", + "254055": "0x08b7b87d328a90f11c579b54290a922fde2bf1f82cfbc8ab65c6b8cedc148833", + "254056": "0x313bc0990f23436ab29a21b457d493ed883083cd41a4bf84af99ffd0cf01b32b", + "254057": "0xdea9c24f93c8dbc5b177e80014ba36773f8da79ec3f4788bb4ac2169953164c9", + "254058": "0x7d9f0cc205e88c743413c638c9af8982a6cbe5a9a00d8395944ffd497ecb1499", + "254059": "0x53ecad66ed9c73b543bfb3bed64aa67fae018382d20c62bc51393ddeeebaec3b", + "254060": "0x9d6f638f7fc2e1e8e2ef11736f5fa90b1cf56a71858e3fcaa1ab0337cea85c1a", + "254061": "0x063c1e0e07fcfb6a2160487cf71bab7d1d55255a542c1fab44bf79253ceae66e", + "254062": "0xdd8712ebfec22470880d075c1551656409750ec00c9b9aee016bec08721670c3", + "254063": "0x3ec299832d1f4ae20fe25ef3c74c6eab62bf55a0f86fcd6034d26fdbb3f83274", + "254064": "0x989830679c98e4644b8e3e69f5c9043899815ea7bb59b12c711f4e1119cad05b", + "254065": "0x3bf857eb755e2c8573ea955222ea9551145b2694902c4bca2f268f1b94232115", + "254066": "0xb7b730ab42afddf8952a109de4075784fa0520374a812eb20bb6b3343657ce9e", + "254067": "0x943f56384f8b513b34d2d6bba42d0f7967bbcbf7cfd90ce0d885f7bb2f2c59df", + "254068": "0xa665ed49bae7c637dd0a9ea6307a3d6e32ca12d903a89227d8ef1a618c7f8bc7", + "254069": "0xab5eec730756fa83c3d5f41a881b6e4154711e63955b15b7e5b4fb69198900ff", + "254070": "0x24b47fb1c015d62b49d7b98eb7ad3f80b6068cc7614075582461af3170d458f5", + "254071": "0x98cc0b29ecc275fc5db241ee108d95f257071ba1854af65a8e610b3db50adbf5", + "254072": "0x33f950cbd14defcd2dd35552e93ac9a185aab966419cc9f0d7794084421ca52c", + "254073": "0x8d8e72e7727d4852ba5940d5a58f3391513c1547cdfabbe4fa6e6b4718e89247", + "254074": "0x114e792d680d88c30b0a3dd740cd8343dc5cd45ba6b853d81a0cbf8d2f0e7025", + "254075": "0x6f5017ee317b779e245bcaa63067483e23e22b2cc5100e4cf56345a12413969f", + "254076": "0x3b91bf07eb6389fb4b2a2f7f286622a613c9aa5e9bd7a1c17e8f6e41195011f6", + "254077": "0x2cc03b9a2e8955f92ac9bed34fc94de2effda25d44ae05653f1b427416f4a222", + "254078": "0xf251a73d561b288eeb3ab55690745efa76b613bd009049f921941a8ab53758e6", + "254079": "0xaafc9455cd37ccbde5301f635c320941de9156801aa8ae6377bca5274fc7525f", + "254080": "0xd1ce883bf8ee53362044a7e0c91d3f619f6a72059e900be01794242fb677d9f5", + "254081": "0xa8367082954b1b155683fb5bf1a135ecdba1951f18bad51821be2b2e6fa8ce8a", + "254082": "0x534cb9ce63647ac0fd43b33f4bc2233b5007c4b2683f429520a3e71942bd4419", + "254083": "0xc1a3c8a452389f4f7a68ff82711849ff48f66f96dd5c3deba3a685717a9eb9a7", + "254084": "0x91506cd29e6429dd8b8ffdaf19891c3f38aad50a1c6c28d99d227a2323c5203b", + "254085": "0x524181d85e185f3d25c6af43aaddc5e8332915a78aef247bcd2bddb9a8cd4e85", + "254086": "0x7f8c4b97cf9d933b0822205130e96db07167d687769bf33443e838c6b673b037", + "254087": "0x76c600b266c55c2290b14b0004d7de19177edd938e23789b288e5018ade4e564", + "254088": "0x7cd18e0014c0e1bca4fb68887496f4c3b45359e33f64656fd623709f6bae4696", + "254089": "0x63c0547be41669c834065ced830f8ff61018e8ce63897b0a7e1354282e10c2f7", + "254090": "0xbbef0f77691ed05ae3dbf3dcd4c717c111d2d7082f3b903eded4b1b8455e6e44", + "254091": "0xbe66a276766732d659b580f41a671b55b6d26ec98938e8a02c2b2323c47c5f3f", + "254092": "0x8dd63154a1d7dde59e233d28bb488164d0ee2704b7f940027074ae8e79ff56d2", + "254093": "0x9007eb72fdb0d68bfdb7846d20cda5f276471f229764ad9093bd2aabfac5ee78", + "254094": "0x0d5aa6a035eabe65a3d58c99789c2effb45da56bce1eb132dcd79873c24c02d9", + "254095": "0x83a9bf0fb5f8e89ecc9e8abfec96c90deca84b495b17b376a7d44d038a0e1745", + "254096": "0x0ee606e65bd974fb3f2ba89a386a4748d2a3afc24f897aa8919fcaedf774bb4d", + "254097": "0x744b1b39926a3650f01d530a2700b2d00fb13f1cb65f8dd8c1780a4392b82588", + "254098": "0xf09df5de4cbeddefa2df18844b94420ed206fc340549f4f97b0a02134c21f1c7", + "254099": "0x1776f448fcf675cc23d1e2c22b6233856a8ef9a92f59e014f8c53750be8a0717", + "254100": "0x55c54192772dfa7ca2cedcdbb8c4441b41aeb4ff08735150664ceb63ccf752d3", + "254101": "0x30de5bf9f43dbddba65a57afea6362bbdadbcc77d612ca97d8acf469fb7759eb", + "254102": "0xc54591701f743e6a20f42548ba9ebb826c7cc6d869d373baa55db60f04963235", + "254103": "0x52df87cfc24d9a7d65edbfa8da032796557875072f6de3fcccf4fb92c82534a9", + "254104": "0x3cc91fe60b9ef3346a9b814b1c92d45f9ee545fa2d28571f67632b33a42e63ff", + "254105": "0x1aa314a634503a4792536cdd0c1b0da211f370e73b398efdecbc34795eecb579", + "254106": "0xbf62a79aa6c5f150ecadfafdc13358248c9d0891cb6d5b31079261d3316f33d1", + "254107": "0x850219a80ced9b65a074ace745a7da75afdc2ccc1c3cae08ff879b000ddd3600", + "254108": "0xa908f76b9e6a176929a8a39a2863aad942839240208e1fed56a6841a415ab7a1", + "254109": "0x180df169cbc48a2201a4987307464026bfd9363958c24f2d118044309b062391", + "254110": "0xa7f106ac5e877ce7964c98c3c47ca55c61930b7f95f9ed5b73d4fa8048a483e6", + "254111": "0x5557c43ab21ad3393466cce7362b64a5b512461fbd993ce8501248d6ad7c5271", + "254112": "0x09d90edbd8d818158c4fac56d4525af9d12ef163a05d121d95aa3dacc1446f19", + "254113": "0x288f48d10b02e1475d8b954fb4d162d436d9ffe33d0c0ad43bcce0223893ee88", + "254114": "0x1d555c73c74b78fe79009bc0b665e1a9dcb521d1c672bb6702223997732c31da", + "254115": "0xb4283e432256060452e6c4888d22f5c22772df4a30f8414e33346efe7deb56e6", + "254116": "0xb5f789868d8b48271ae64af8ac9a30415286cd3b8bd55fe691e282973e3115c6", + "254117": "0x2ace1904308d82470b2a8f0ca7793b9a096c3bcb4b12cae96ad02b0d0b91f330", + "254118": "0x9fffb3efbda6ef6f04f8cc65a945b3a6290d84dd4a5e82f2355bc79cedf2b94b", + "254119": "0x804da422519ab9ecb6dbb25cbcc905ce2bbfbc6a4ec6bb7f683a030be70bda5d", + "254120": "0x0e3878eb19d22d67a397474f28d22b77448d54b56af89cd6d69de9744262700d", + "254121": "0x1f05e70603c2ddfc8bab791ab78925a754d244c6185daaa008714802b0ca8f65", + "254122": "0x8b89bd4a5a2bf5da8599f0aaf56d5473e29da19c6af16bdb804c1b41b450ac4c", + "254123": "0x937ae77b4aa1f8789b5fd4236dccaa29174083db1ed40fb12f8d985da6ea9d88", + "254124": "0x08292a245bd2443f67b377277c6ff392840114bb474bdfff094a92b810daa8ee", + "254125": "0x60f49742aaf99eb21b90c9f5d87f426b8f083c59a30eb43d34e46fb1d3bd9940", + "254126": "0x06d9058f44b41ba0609f27de303c2e08612b108d5516f09ea97d12eab3cc5188", + "254127": "0xc49bfe83cb9abcbe832fe6f1c0e38c2043fe14fd68c6de86588a58b5f2a6c782", + "254128": "0x28869b77652ad95fb99ae0faf8e1cf14101294d1d5e1262487e975c90b3bce2a", + "254129": "0x8c218127d38ca1d58f0951b222bd18042af63c243d6866196c591367b8a8d37d", + "254130": "0xbcca2687646f2c1937b5743fa9144909f10f9712dceb374dba808f6bc8021f01", + "254131": "0x772b6900ff72c950472d927819198e4a1311f79102fb2fd4118fc1b804a5f17f", + "254132": "0xd210774438ab168e8f95a742b1b1573662572d9ba5fcacd3927d84d8ecaa55e7", + "254133": "0x6ef2a18bd2158fa61e0dfe9917425c6af0cbd569ca643849372a9e3460c4f6ad", + "254134": "0x6dd8c5fcb753e0094549461f592e47c56d09ba1d695ac735702b38cd7edda159", + "254135": "0x3c8920f9615906ec54b6570901394dbffe4c7910136e23d90eb2a879d3805189", + "254136": "0x880508600187588233da82124c03674bc82584b664e20b28afea9317d7a4c015", + "254137": "0x39b4124ad203f110d1ab3097e5d8fbe22be28aec3c7fb0fd5c83f6c634a20f20", + "254138": "0x4736fa52d7ce830d0cf765df167d3c4d49738e697bb2f244551ae34f558e062d", + "254139": "0x1b0f57838af0731cffb9ed7676c52e33a2be649cf6f91410ef255bc990209254", + "254140": "0x676d6df4c69d2110677d0002f6ff8b2ddb567da3ee60b0a6ee87d00d3bf75379", + "254141": "0x333c4c6f2b12943aa17776ba72a566095c8f9678efac29ba7a7324c325faf176", + "254142": "0x4b62e6bf9f4a2d901808553635f69d1d982cf386a71637b529980f50f9df4f6b", + "254143": "0x47d20fa4f2e43608edf69862bf0d2c04dec612593235a39cb098daac65829e30", + "254144": "0x958862f0eb9d2055e3bbc50c4b6bc5464c279f7c8ecd452cc92dc1e921b0f908", + "254145": "0xb458e4626ad33f37c825a5806af56d9b2bd9cf66ab87957435675391ef521d6f", + "254146": "0x15e76ced896d1ed56ddcff68e71b2fb1b28f9dcaaa2378bcfd202ac1886e7efb", + "254147": "0x61ae19a83e6f293ad4af89ff75f6327c5047aef8b62279651e8e1c6bf1ee0593", + "254148": "0xbd20487dd578f1abc90998da5b8139c8fe841f9fc381c8024b7ade5bf13e6f28", + "254149": "0x229bec8d047268d2b130aa726f87d6207dbe2f0eddccb4333ceabb2aea50e93a", + "254150": "0x847e018de0560f4718293ef4ca8a952957afb57a3a7ccd9200ba32f3830e4fd3", + "254151": "0x6cf9eed7505fed3c6a35c58a081bf89b1a0a4eec02fe193e671998d3c0589d89", + "254152": "0xe6c147e1d9107aacac78dac53a28dccddaacf80ff177f9ed3384431c8122a1e4", + "254153": "0xb72524d60d1a8da9fafe1c8f9a5cf38e2437fd038d40ad085a9df5bf930e0190", + "254154": "0x0f43d3d224579f144054434846859a26e09ca78cae83983d5ef59a701a805761", + "254155": "0xa3f8ca2d78caeefedce060f70a60676da44494667783809eb4e6f9ddcab5c9f5", + "254156": "0x5f90c7d14d0ad23f1b26c6c664d474fe1d6e510cd8d0efb9aff3d2a1365d9a1c", + "254157": "0x5b9c22aaba0785ccd1fed57fe6253a9bab522bbb9a21481920358283a2fa38ed", + "254158": "0x3ce3be5de4e83d2938ccff0f30816ae1963bb12f68e9b97f26aac7e3a16bd79a", + "254159": "0xfb9a0a14a48820af9c4146d32f0aa54691d0fe09e0d92d75613893a99917e1d5", + "254160": "0xdba25253e5b9ca6e7710c81cc39a48c25cd98eb131377fe4be983904c2afa1fe", + "254161": "0xf52f93c675faffba47d2ece16440661015a1d32532b3a930dddcd4c8d58bdee6", + "254162": "0x6d452b1355e73fd26ae329a92e7169c641d667d14a6fa88223627c2067c11e12", + "254163": "0x7917843f7baca0e311511b83f91bc86bdb8c00638e17cf05d2c7d90bb09645ac", + "254164": "0x229b612b7935f34e11ca5a354f21410a3d3af2ee7e92ea93e3464cc0bb6dc78f", + "254165": "0x6819854a98d2c1e0ceb962aedaee0b1ab2570c6006f100a9b2e222d60aaf7d49", + "254166": "0x2ac7a9a449f2e5054c586fb57f6a1372397d5ce999ffb41d1b9a77ad15ea3414", + "254167": "0x755ab4e575593ebe9035396dd44ff5662f066922bfc31f390e126ddca2f476bf", + "254168": "0xefc4866ef8061c2d5d23520e13f2b835c85c0af93ccbb859c2b131fd6e289976", + "254169": "0x4ec88e9967413f18a0e5b3608f3c02c05bd729089c3ec3a4664e7d424ce04e50", + "254170": "0xcc9f8a148decb545d8cf0f40c0706f8e7104620c4c546addc1a218aa1f81aa90", + "254171": "0xec30a5cf49bd9ff32433d40276138be2cea4c391b1df9e277068f69ae73652bd", + "254172": "0x62b523f3cdf40547fca3cb7eb91815e6df9b830574ffd9d1607d4abb6f9f3a73", + "254173": "0xef7424d2c7fd2a9bca7c0d4c55503905c147b2b70c9bcad57db4989c46b2089d", + "254174": "0xfd9e2fa11e4b9106860894df001f7394df04d79e84a1f10ef09493c13c1c04f9", + "254175": "0x4114a9f78469ef4bee3d3af1ad714dd57853e810a13162fd0f1fae6ddd54d3ee", + "254176": "0x2aab88ba9d0f2a5745416daf9417e044b42ff0d9f853323ab2d07a09b5c67013", + "254177": "0x88eacb8a30b0ce70b12716acd86bd2241841959b7bfaba7ca522e0ee7c167e01", + "254178": "0xb61b699d55187fbd4125339f84734c7956a7713c3ba11688f766e1539b186374", + "254179": "0x10fed5c2037b71bd48943f60cbb19354fadbf9a0c1a167e5bc1688acf5eb5e3f", + "254180": "0x980a743d8fc1c14f0dfe3127979f9f8e5853797603756521e1ab7b9e3ad27c2a", + "254181": "0xc7fb787f2f23a48d5d5ea1e595385f0dd1d5159b338775516b2c1d41c16ec761", + "254182": "0xbef8253c05530905f6983414f7cd025a39217bbfe89b631f1c703e5b1b71cc84", + "254183": "0x302659ade583955e3bad7e63bedb7fa18cd356de2b3d1a169ec315d6e5a3d0ad", + "254184": "0xff8cd55b91b961218a8f5952026179d0bf0570618e36ed4c427bf2d60fe317a3", + "254185": "0x30903d2c9d4b8e937b3a572ba2a209f360598b1ccdb4817211a2df0571ca159d", + "254186": "0xcc75fe2fce32a781d72072abea99a2b73aa0d7fc8f46b29143582b90b92a8a90", + "254187": "0xcbfc65750b3c21d96698718589765a34863094955eaa4566755895da95fc9b9c", + "254188": "0x1712c42d31098308d6e1b53205ae12b9a3b300f267847932afcdd85484058931", + "254189": "0x27a0e9b125d0a09bfa76f48210a5b9d7fc58a02087cf23cdf6b28e8d93b566fa", + "254190": "0x2a8f25eacab2717a50ca43d8b31bed5bbd297ac8879b67d6b2a8c4b559281460", + "254191": "0xeb67c72a0bfd579c6891d5b2d3ad8b6d68dfc519eb59efbc744b300888d3e3a2", + "254192": "0x04aa9d55b48e28fc457ae2393e8c11d294ad70907156566f853406d3da27b386", + "254193": "0x4502a753bb5a68736ab2f1acccff5518430df5e63a0170dbad046326358802dd", + "254194": "0x99bd5cb9bb482243edd3f914a978dae70aa6af53997238d0fbcc4428c52d9c08", + "254195": "0xa67b0130b7b1394b1ed6d898a22f3ab071d5c70ddf2f290384f70530234c9c99", + "254196": "0x3fa85b2ecf6127672cb04e9a1f599555804f70feea8dba09e6601a091f378880", + "254197": "0xfb67e7ebc461c38a8f5379b083d6eb59c94cd15c23060e6eb7eb47c71fa0abe9", + "254198": "0x6457550e55f24ea4929445c6135cee9d87ac8944bbf50fbd93a8d893619fd8bf", + "254199": "0xda3c364b620188a8f5cdf70da86a541d022e6249109b06073b7a336108b34fd7", + "254200": "0x05c63b07077eafd60a02723303776d6a57dc45605463f3645ad7ab4c1989291b", + "254201": "0x91905289af8ce384d5afa6c20cd6557a343ccdac9c9c1c5d13820eb2bdaef1fa", + "254202": "0x255cac9e079cc14cf0d55604329e239720557afd1e0f986e45418c20d85bdb8b", + "254203": "0xaf859bf5ad02d19d1d4c11469173b6d64040bbfd229cd2bfc840a7a486b5ee09", + "254204": "0x0bb505d20425e2f845ed9c7eeabdd132f9fd7c1607fd2d42389d1ec2534662cb", + "254205": "0x0d8435a9cff7fb00cf803d666fb4be7b07a919130084d7d14555190f4388d92f", + "254206": "0x04261fcfcc1ee48197a2ace46fc9cbb158f41a363f993cc566bb87c101150c22", + "254207": "0xb4cd463330d7dd596790ec29e6ba28633ba9563157007fd0e152c54a13f94bb9", + "254208": "0xcf6c11891d79ab5ce1a8735c6fa2554dce8da8e0a0dfa9a9b563034f62972ba6", + "254209": "0x190ec8c8a7c587bdbfbf35f4f975ca6ddb89b41a2b5e7512dbed30b9f0923a0d", + "254210": "0x027c29a9d65708a4f4b678d15ac543378f8f78897a28f30ce455b1edd1bcb9a6", + "254211": "0x595fd8392ecd427501d0d7be945a56fc73a65818af5f606c92b995aa7b41613d", + "254212": "0xcc92045e7ec1cbc57968a140faa7482dc785a45f56405dc36ae6e1d05e1179dd", + "254213": "0x529a0dfd6602381c238ba7d4d8f0107fd5ce74942eb0ec77ba0b37659191d94a", + "254214": "0xef137cef6df1471072e5071b1f73c6611cb73f476cb8123425529abb826ccabf", + "254215": "0x7aac3b4b88be2c680e29a6cfdb7091aa7e3af35e41a9ab755beac435ea64b935", + "254216": "0xe7e368454d0e8ed744d808bc69052c72a75f3819a3cf75b921d7d0ab95b5cc29", + "254217": "0x937f0f1718cfd17e505ce36f891d592070afa2049e2f897e8af87b69eb56f342", + "254218": "0x84bb042e765de65a689a3d58202d639a64850bd6aefbd0d1e90058196f874517", + "254219": "0xd27618753a76d0fb7d09f9e09ffdddf946a0dcb4de0cd79a18fe9c538e23b3a0", + "254220": "0x29c8f6967930cf862029461db2cb0534e521c6291a6f0d23a74befb714b5ebf6", + "254221": "0xda35acba1faf4e445c280442e18bdaea359b3c253b348359b9968c98ae53c986", + "254222": "0xc6fc8356eb823fe131aeba3736804b68f964a7a579c5f324e3a4c4b639a34619", + "254223": "0xe4a3c8107f916ccdaaf772e0d882478561d0cd5dd496c70a0d5a4240c6e35115", + "254224": "0x03b97dc801f4aef71eaf06fa39c12dcdaf00295b24bf843af3584a851db158af", + "254225": "0x7e90ef2ead2ab921693b89483d3d01f64b69ee326668a47559b271aea9034470", + "254226": "0xe73be9b7be4d6133997129b7855b1e6049072aca21493d10d7015536a55b6202", + "254227": "0x181269790ac7a09a221aeaf26092a5a96428dffce726c51829914e1d8aa6cffb", + "254228": "0xa990c6af9bb4823b24df3b9b476e96ae986514196b7188db1ad8675c1bad133a", + "254229": "0x114f2aab33949e4ab96961ad8dd1015b1045a46a237b6bd8c5db37876479a490", + "254230": "0xf80976caa7ef1bdeec75cdf2993d440a814ac56d3267b3d80d7a0c6dde51306f", + "254231": "0x5136ee969c78b9743a281c3e1b64f70566dde0059b1a8dc413f6cf282b75419c", + "254232": "0x226699482dcf407e15529b166b5da191d3c938b0e22209bc97fca6117e011a94", + "254233": "0xb19485e02d3fcefecdbf632d69e12c6fa68b12ae1bd7ffaad4f34a63e2062993", + "254234": "0xb45060f5854e946dfd0407ddd12c056fd7ab748e8074a318af6d593f47d87196", + "254235": "0xe43516b2e1c9f50fcfe48ef120a43f9a5f308bf3a03eb93e5b2b02de575fdd85", + "254236": "0x62fe2c801ca3ea11f4efc769c903f1850feae060d166b2780273e0de36ef11f6", + "254237": "0xaa97396ceede3d5e6a6194e9bdea9e51157268487ba3ad87a01a7e4523ab032c", + "254238": "0xe677f58f7ff6cb71ea85874e3479ad6aca4b1c5ba03ffcd6fd768028ac973fc8", + "254239": "0x191ca284681272e0d99ddc547e2f84299fd8760e9feaafc274da532751596360", + "254240": "0x2db5c4aaeda66a2c6ce36638c31414cb48d545fbbf055275fe00b944deab5ff1", + "254241": "0x30b2ae28d5b62e11f89ec7b518d306d840bfae1356e1343f4e513f4288a80ed7", + "254242": "0xeed9c4af27855c7e6c3a9eb7a8cdbdb99f77e2ea8ff1c60472fb6dc812f21295", + "254243": "0xcbd113360afec5506f07fe0158595cb89de5915b7a04f481334423d33ac04f77", + "254244": "0xec89a841abc25ed83bce8e4dece37615e73a17cc68e697f2aab0538967e6dee7", + "254245": "0x8750998f251188aa782ad88a269613136e13163b808e6d86c175fa12fe89e198", + "254246": "0x3949efbd1e67390cc9b05e0bd9b3579d3c4e52599aeb6433f56c15e7ffa5bde2", + "254247": "0x63958f93098b82050dd936e9dceb1579e045de927a32f481f10bfc82153e82d9", + "254248": "0x33a5447294234e86d97b706d8b5c32ff535334f9c5fde6a832cb3ed9e7e70a53", + "254249": "0xe8982505a9f5b1921a16d172c3291918be118beb0474db3d76aff57ac61f2d8c", + "254250": "0x9a4b4fb0c5879cd71153e8d3755b6e37cebdf8efea59e1f7503cdabefbaab419", + "254251": "0x48d48c37c0cdf11fd592f001c3535fffec7000d79ad3711bc0542e17607b6f59", + "254252": "0x2c2d53a3dbce052399db3942f353caf73e4d69e73955f4ca26506337711e050b", + "254253": "0xa71e2795ccbe6a71123924fd2be6c1ae26dd88d80edae6023eff5f8854238b7f", + "254254": "0xd90d7abd127973be24b285fefb7b6f692df827cfaae6f6893f4afc8556a00c8f", + "254255": "0xf840ce12169ec7c3a882aa78ede2d91852cc01ae2e27076535c4d533a049a6e5", + "254256": "0xa5f37f58ba4d5387e23ecd0141ad8c30cdc91e222b232898b8b18bb2d2862993", + "254257": "0x6a41907f66d6c6dd33372c77bdd2fb527da8fd24137a38abbc5ab6424d773d14", + "254258": "0x98af953ab95f84af13f977b57bf84170f39128bfc30b17748e0b71df6990e734", + "254259": "0x856764bc184093cdf216c51c1a669f0ff5f384b5f55c88a50ddd99a46f112f33", + "254260": "0x614d1df124e3145027afdb090521100fb098263d796f25ef7f4aa2191f90386e", + "254261": "0xe4dcc9156ea3b471a4cda9d95a889d51c10bf32b1c6f3e0a41c07ea60473c296", + "254262": "0x1b1fcba870981e93855be5ad680f3414728309d23d7f35b280bf3d536055c3fc", + "254263": "0x5b954f3671a4306ce79d7bc64cc2cf02a5cbbf50b8aab14d1f6c7a66e14ed23d", + "254264": "0xf71475425852f270d97a7a7ab721e60e9d8e6731efef8ab90758c7d881dbe686", + "254265": "0x9cf6644fec85eaf4370038fee06efa648e169572376e69dd5eeee94081f65a31", + "254266": "0xee8923a3c19bb4bedc077c8e094dc0991a57fd308589a445af3029c6a8b70248", + "254267": "0x034a4812250f89d06b4a4eeddac68d0929cf9abf4648e361aa93e7ebadd32a3f", + "254268": "0x0cfebc0876c679192cdb0bf25c205a6a046db6a8f32cc02ade52c33cc58e1a5a", + "254269": "0x732228f5ccf4c52fdc0cd8385675425bfb39fafcf6a19a3734d6c872d4e90e7c", + "254270": "0x132a64af39d99da47831adf77e0a883fed92dd6cd33b863e6dbdd3409e5c11a2", + "254271": "0x68c46dc8c2f3aee2ec1999162736465965f85d4af8ed4d439dd1ee79660d125b", + "254272": "0x62bb256436b09803a694d66dd57a86244c2a9b3d9f61471bac8116b87e0440c3", + "254273": "0x47db9a800632dcef9c26cd3a6ace949c21808007040d11fce0cc40eb83b5e794", + "254274": "0xcc1f12a4013d122ebfb397f3c8c1102542baaf71d1e83ea691b4186c2640aca3", + "254275": "0xce3f1d03b7b8ba062f87493c470a6294326481f65e8cbe531a11923afb411261", + "254276": "0xbd689c92697150273a220bb26886e6219f4956297cd562c8a59558005261a3fe", + "254277": "0x143461d3e528e33c6d468a2b3e67a2662bddce58a3288143e2181aa67ea8409a", + "254278": "0xc31bd5086ab03989a65597ed06fc6e4d79cca630f8bcfcb2c1ed51c9477781a7", + "254279": "0x3d8f51b84b5f38833b1e43d0ec5e0e7937410078ade758ecc3d2d1f28ad5713d", + "254280": "0x5cf4fdd31c6eaf0a88bb7f057d61120fc5cbf2e8b134f38638493ed1e96ae7c2", + "254281": "0xd547c9723dc50bb546af2b70c32c2e2d24bc2c94b26b91900f893af753b19dae", + "254282": "0xa47b68eb33cbd46a386f8fc5e2262244edb440581c30ff338ece7c5e48ae866d", + "254283": "0x6a9094ce40c2c549719d3b3fefc13479ed3e8a4dbcdf127f3382ffb0bb050cdb", + "254284": "0x1c36772b15b3a5a91f8c7fa2e24a81f8834d86048994f5acf4fe76f4e12c8708", + "254285": "0xa4d443c959a87c9d0ae0c16d0246e6262f7f4663f72bffc72d3dbfbdd79e4c9e", + "254286": "0x0be05570d281f12c7d9e91db4b99528a03f401ad5e0bf77fc6a58ea76ae619fb", + "254287": "0x90ebf4a023ba3da63d4e8a0bc0a45e8c47501bd05f358c8c6651a54492ea59d9", + "254288": "0xdea411f8fc12323c0578f40420bb65401456f380804e64e3060dc22f3ece12e8", + "254289": "0xae3a5686d8d4d60f69a5f217a962c5cd8e256aadf08c79077c856f5716407180", + "254290": "0x19ba1ef014ecf4b48401c809149aa05db7b77b96a5ec8f374d30e5e31aebbb2a", + "254291": "0xba80b13a35e8a977d918fa58c4d797676abb062a50b2cfc174cbc4f514e9ba97", + "254292": "0xfca95955ee875e3bc3aeaeb2f1e69ef1b9b92eee3ac625c12b09cf028167318d", + "254293": "0x4bf841483d92817aaa20ab2a7e0ed11bf4812247d721b7d55f6d1c1383fc277c", + "254294": "0x0014c6787d259273ef3669c4ec7cfdbbb6c517de23ae861be584b533810ae09e", + "254295": "0x5ae58bfafc4813ede478caa63b87444f01b9e852b57da5225f74a6a0a5e25633", + "254296": "0xf3a1a8db998fcd113063fdf801cae8aa5a450c12d3c72eda61eb56b354bc18cf" + } + }, + "prestate": { + "0x0047a8033cc6d6ca2ed5044674fd421f44884de8": { + "balance": "0x0000000000000000000000000000000000000000000000000afeb0f4d1abeb52", + "nonce": 216, + "code": "0x", + "storage": {} + }, + "0x1430236a73a97654bfb6851eb7e8facdfbe2cdb5": { + "balance": "0x0000000000000000000000000000000000000000000000000000000000000006", + "nonce": 0, + "code": "0x606060405236156100a35760e060020a6000350463187c5903811461010d5780631bccca141461013d57806327e235e31461015e57806329f8df0d14610176578063444bdb1b1461017f57806351870150146101c857806367c18aa1146102db5780636d4ce63c1461038f5780636e723e24146103bb5780636f7bc9be146103c457806371ad7221146103dc578063a32da9d1146103fc578063e8b5e51f1461041d575b6104796305f5e0ff606090815260009081908190819081907f909c57d5c6ac08245cf2a6de3900e2b868513fa59099b92b27d8db823d92df9c90602090a17326588a9301b0428d95e6fc3a5024fce8bec12d51600160a060020a0333161461047b575b5050505050565b610479600160a060020a0333166000908152600b6020526040812054819081908190811415610793575b50505050565b610545600435600681600581101561000257500154600160a060020a031681565b6103a960043560056020526000908152604090205481565b6103a9600c5481565b6103a96000808080805b600c548310156108f1576005818085838110156100025754600160a060020a031690525060208190526040822054029093019260019290920191610189565b600480359081013560208102608081810160405260608381526103a99460249491939085019282918490808284375050604080518735600481013560208181028481018201909552818452989960449993985091909101955093508392508501908490808284375050604080519635600481013560208181028a81018201909452818a529798606498909750602492909201955093508392508501908490808284375050604080519635600481013560208181028a81018201909452818a5297986084989097506024929092019550935083925085019084908082843750949535945050505050600160a060020a0333166000908152600560205260408120548190819081908190111561071c57610710565b610479600435602435600160a060020a038216600090815260056020526040812080549082905590808311156103345783600160a060020a0316600083600502604051809050600060405180830381858888f150505050505b5b600c5481101561013757600160a060020a03841660008260058110156100025754600160a060020a031690911415905061038757600080826005811015610002578054600160a060020a031916905550505b600101610335565b33600160a060020a03166000908152600560205260409020545b60408051918252519081900360200190f35b6103a9600d5481565b6103a9600435600b6020526000908152604090205481565b600435600160a060020a03166000908152600560205260409020546103a9565b610545600435600081600581101561000257505054600160a060020a031681565b610479600160a060020a0333166000908152600b6020526040812054141561046c57600d543390600690600581101561000257018054600160a060020a0319169091179055600d805460010190555b6040600020805434019055565b005b5b60148410156104b457600494909402938084368110156100025760f860020a903581900481020490950194506001939093019261047c565b600160a060020a0385168082526005602081905260408320805490849055879550935082908402606082818181858883f150505050505b600c5481101561010657600160a060020a03831660008260058110156100025754600160a060020a031690911415905061053d57600080826005811015610002578054600160a060020a031916905550505b6001016104eb565b600160a060020a03166060908152602090f35b73393519c01e80b188d326d461e4639bc0e3f62af0905080600160a060020a031663a0a1cddb86612a3001338c8c8c8c6040518760e060020a0281526004018087815260200186600160a060020a03168152602001806020018060200180602001806020018581038552898181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038452888181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038352878181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038252868181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050019a50505050505050505050506000604051808303816000876161da5a03f11561000257505050346005600050600033600160a060020a0316815260200190815260200160002060005081905550336000600050600c600050546005811015610002578054600160a060020a03191690921790915550600c805460010190555b50505095945050505050565b5b600c54821015610757576005818084838110156100025754600160a060020a0316905250604082205402909201916001919091019061071d565b346005028330600160a060020a03163103101561055857604051600160a060020a033316908290349082818181858883f1935050505050610710565b5b600c548310156107d3576005818085838110156100025754600160a060020a031690525060208190526040822054029093019260019290920191610794565b30600160a060020a0316318411156107ea57610137565b9150805b600d5483101561082c57600b816006856005811015610002570154600160a060020a03169052602052604081205490910190600192909201916107ee565b6040812054600160a060020a03338116808452600b602052309091163186900391849004919091029182606082818181858883f19350505050506000600b600050600033600160a060020a03168152602001908152602001600020600050819055506000925082505b600d5483101561013757600160a060020a0333166006846005811015610002570154600160a060020a031614156108e5576000600684600581101561000257018054600160a060020a0319169055505b60019290920191610895565b9150805b600d5483101561093457600b816006856005811015610002570154600160a060020a0316905260205260408120549190910190600192909201916108f5565b5030600160a060020a031631929092039091046064029291505056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000000000c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xb9cdc18f79fe1b65ae263fa10e093f00c4df64aaf6a5862b99aef0db1cbd89a1": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x1dcb8d1f0fcc8cbc8c2d76528e877f915e299fbe": { + "balance": "0x00000000000000000000000000000000000000000000004dd8645baf57193203", + "nonce": 24649, + "code": "0x", + "storage": {} + }, + "0x393519c01e80b188d326d461e4639bc0e3f62af0": { + "balance": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": 0, + "code": "0x606060405260e060020a6000350463a0a1cddb811461001b575b005b60206004604435818101359283026080818101604052606085815261001995943594602480359560649593949101928291908490808284375050604080519635600481013560208181028a81018201909452818a529798608498909750602492909201955093508392508501908490808284375050604080519635600481013560208181028a81018201909452818a52979860a498909750602492909201955093508392508501908490808284375050604080519635600481013560208181028a81018201909452818a52979860c498909750602492909201955093508392508501908490808284375094955050505050507f1c72891789b7cf96081c1ac309384760b5cbb5b2b93a3e0adb1e05119925f6eb868686868686604051808781526020018673ffffffffffffffffffffffffffffffffffffffff168152602001806020018060200180602001806020018581038552898181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038452888181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038352878181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018581038252868181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050019a505050505050505050505060405180910390a150505050505056", + "storage": {} + } + }, + "expected": { + "status": "success", + "tx_gas": 94849 + }, + "meta": { + "source": "rpc+trace_replayBlockTransactions", + "rpc_url": "https://ethereum.publicnode.com", + "trace_includes": [ + "stateDiff", + "trace" + ] + } +} diff --git a/tests/evm/fixtures/legacy_call_repro/cases.json b/tests/evm/fixtures/legacy_call_repro/cases.json new file mode 100644 index 000000000..0f0a37fd9 --- /dev/null +++ b/tests/evm/fixtures/legacy_call_repro/cases.json @@ -0,0 +1,13 @@ +{ + "description": "Standalone legacy CALL repro fixtures.", + "cases": [ + { + "name": "legacy_call_creation_cost_block_254277_tx0", + "fixture": "block_254277_tx_0.json" + }, + { + "name": "legacy_guard_block_254297_tx0", + "fixture": "block_254297_tx_0.json" + } + ] +} diff --git a/tests/evm/fixtures/legacy_call_repro/schema.json b/tests/evm/fixtures/legacy_call_repro/schema.json new file mode 100644 index 000000000..1aaadbc07 --- /dev/null +++ b/tests/evm/fixtures/legacy_call_repro/schema.json @@ -0,0 +1,212 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "DTVM Legacy CALL Repro Fixture", + "type": "object", + "required": [ + "case_name", + "chain_id", + "block_number", + "tx_index", + "tx_hash", + "revision", + "tx", + "env", + "prestate", + "expected" + ], + "properties": { + "case_name": { + "type": "string" + }, + "chain_id": { + "type": "integer", + "minimum": 1 + }, + "block_number": { + "type": "integer", + "minimum": 0 + }, + "tx_index": { + "type": "integer", + "minimum": 0 + }, + "tx_hash": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{64}$" + }, + "revision": { + "type": "string" + }, + "tx": { + "type": "object", + "required": [ + "kind", + "from", + "to", + "nonce", + "gas_limit", + "gas_price", + "value", + "input" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "call" + ] + }, + "from": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "to": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "nonce": { + "type": "integer", + "minimum": 0 + }, + "gas_limit": { + "type": "integer", + "minimum": 0 + }, + "gas_price": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]+$" + }, + "value": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]+$" + }, + "input": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]*$" + } + } + }, + "env": { + "type": "object", + "required": [ + "block_number", + "block_timestamp", + "block_coinbase", + "block_prev_randao", + "block_gas_limit", + "block_base_fee", + "tx_origin", + "block_hash" + ], + "properties": { + "block_number": { + "type": "integer", + "minimum": 0 + }, + "block_timestamp": { + "type": "integer", + "minimum": 0 + }, + "block_coinbase": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "block_prev_randao": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{64}$" + }, + "block_gas_limit": { + "type": "integer", + "minimum": 0 + }, + "block_base_fee": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]+$" + }, + "tx_origin": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "block_hash": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{64}$" + }, + "block_hashes": { + "type": "object", + "patternProperties": { + "^[0-9]+$": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{64}$" + } + } + } + } + }, + "prestate": { + "type": "object", + "patternProperties": { + "^0x[0-9a-fA-F]{40}$": { + "type": "object", + "required": [ + "balance", + "nonce", + "code", + "storage" + ], + "properties": { + "balance": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]+$" + }, + "nonce": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]*$" + }, + "storage": { + "type": "object", + "patternProperties": { + "^0x[0-9a-fA-F]{64}$": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{64}$" + } + } + } + } + } + } + }, + "expected": { + "type": "object", + "required": [ + "status", + "tx_gas" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "revert", + "failure" + ] + }, + "tx_gas": { + "type": "integer", + "minimum": 0 + }, + "dtvm_interpreter_gas": { + "type": "integer", + "minimum": 0 + }, + "dtvm_multipass_gas": { + "type": "integer", + "minimum": 0 + } + } + } + } +}