Commit 27dbdcbe authored by Adrian Sutton's avatar Adrian Sutton

op-challenger: Fix recording of last step index.

Record the same last step value to disk as we store in memory (should be one less than the final state Step value).
Write the proof for the last step to disk to avoid needing to regenerate it even once.
parent cf1f0b10
...@@ -53,8 +53,6 @@ type CannonTraceProvider struct { ...@@ -53,8 +53,6 @@ type CannonTraceProvider struct {
// lastStep stores the last step in the actual trace if known. 0 indicates unknown. // lastStep stores the last step in the actual trace if known. 0 indicates unknown.
// Cached as an optimisation to avoid repeatedly attempting to execute beyond the end of the trace. // Cached as an optimisation to avoid repeatedly attempting to execute beyond the end of the trace.
lastStep uint64 lastStep uint64
// lastProof stores the proof data to use for all steps extended beyond lastStep
lastProof *proofData
} }
func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, cfg *config.Config, l1Client bind.ContractCaller, dir string, gameAddr common.Address) (*CannonTraceProvider, error) { func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, cfg *config.Config, l1Client bind.ContractCaller, dir string, gameAddr common.Address) (*CannonTraceProvider, error) {
...@@ -139,24 +137,19 @@ func (p *CannonTraceProvider) AbsolutePreStateCommitment(ctx context.Context) (c ...@@ -139,24 +137,19 @@ func (p *CannonTraceProvider) AbsolutePreStateCommitment(ctx context.Context) (c
// loadProof will attempt to load or generate the proof data at the specified index // loadProof will attempt to load or generate the proof data at the specified index
// If the requested index is beyond the end of the actual trace it is extended with no-op instructions. // If the requested index is beyond the end of the actual trace it is extended with no-op instructions.
func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofData, error) { func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofData, error) {
if p.lastProof != nil && i > p.lastStep {
// If the requested index is after the last step in the actual trace, extend the final no-op step
return p.lastProof, nil
}
// Attempt to read the last step from disk cache // Attempt to read the last step from disk cache
if p.lastProof == nil && p.lastStep == 0 { if p.lastStep == 0 {
step, err := ReadLastStep(p.dir) step, err := readLastStep(p.dir)
if err != nil { if err != nil {
p.logger.Warn("Failed to read last step from disk cache", "err", err) p.logger.Warn("Failed to read last step from disk cache", "err", err)
} else { } else {
p.lastStep = step p.lastStep = step
// If the last step is tracked, set i to the last step
// to read the correct proof from disk.
if i > p.lastStep {
i = step
}
} }
} }
// If the last step is tracked, set i to the last step to generate or load the final proof
if p.lastStep != 0 && i > p.lastStep {
i = p.lastStep
}
path := filepath.Join(p.dir, proofsDir, fmt.Sprintf("%d.json.gz", i)) path := filepath.Join(p.dir, proofsDir, fmt.Sprintf("%d.json.gz", i))
file, err := ioutil.OpenDecompressed(path) file, err := ioutil.OpenDecompressed(path)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
...@@ -183,9 +176,6 @@ func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofDa ...@@ -183,9 +176,6 @@ func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofDa
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot hash witness: %w", err) return nil, fmt.Errorf("cannot hash witness: %w", err)
} }
if err := WriteLastStep(p.dir, state.Step); err != nil {
p.logger.Warn("Failed to write last step to disk cache", "step", p.lastStep)
}
proof := &proofData{ proof := &proofData{
ClaimValue: witnessHash, ClaimValue: witnessHash,
StateData: hexutil.Bytes(witness), StateData: hexutil.Bytes(witness),
...@@ -194,7 +184,9 @@ func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofDa ...@@ -194,7 +184,9 @@ func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofDa
OracleValue: nil, OracleValue: nil,
OracleOffset: 0, OracleOffset: 0,
} }
p.lastProof = proof if err := writeLastStep(p.dir, proof, p.lastStep); err != nil {
p.logger.Warn("Failed to write last step to disk cache", "step", p.lastStep)
}
return proof, nil return proof, nil
} else { } else {
return nil, fmt.Errorf("expected proof not generated but final state was not exited, requested step %v, final state at step %v", i, state.Step) return nil, fmt.Errorf("expected proof not generated but final state was not exited, requested step %v, final state at step %v", i, state.Step)
...@@ -217,8 +209,8 @@ type diskStateCacheObj struct { ...@@ -217,8 +209,8 @@ type diskStateCacheObj struct {
Step uint64 `json:"step"` Step uint64 `json:"step"`
} }
// ReadLastStep reads the tracked last step from disk. // readLastStep reads the tracked last step from disk.
func ReadLastStep(dir string) (uint64, error) { func readLastStep(dir string) (uint64, error) {
state := diskStateCacheObj{} state := diskStateCacheObj{}
file, err := ioutil.OpenDecompressed(filepath.Join(dir, diskStateCache)) file, err := ioutil.OpenDecompressed(filepath.Join(dir, diskStateCache))
if err != nil { if err != nil {
...@@ -232,8 +224,15 @@ func ReadLastStep(dir string) (uint64, error) { ...@@ -232,8 +224,15 @@ func ReadLastStep(dir string) (uint64, error) {
return state.Step, nil return state.Step, nil
} }
// WriteLastStep writes the last step to disk as a persistent cache. // writeLastStep writes the last step and proof to disk as a persistent cache.
func WriteLastStep(dir string, step uint64) error { func writeLastStep(dir string, proof *proofData, step uint64) error {
state := diskStateCacheObj{Step: step} state := diskStateCacheObj{Step: step}
return ioutil.WriteCompressedJson(filepath.Join(dir, diskStateCache), state) lastStepFile := filepath.Join(dir, diskStateCache)
if err := ioutil.WriteCompressedJson(lastStepFile, state); err != nil {
return fmt.Errorf("failed to write last step to %v: %w", lastStepFile, err)
}
if err := ioutil.WriteCompressedJson(filepath.Join(dir, proofsDir, fmt.Sprintf("%d.json.gz", step)), proof); err != nil {
return fmt.Errorf("failed to write proof: %w", err)
}
return nil
} }
...@@ -158,20 +158,16 @@ func TestGetStepData(t *testing.T) { ...@@ -158,20 +158,16 @@ func TestGetStepData(t *testing.T) {
Exited: true, Exited: true,
} }
generator.proof = &proofData{ generator.proof = &proofData{
ClaimValue: common.Hash{0xaa}, ClaimValue: common.Hash{0xaa},
StateData: []byte{0xbb}, StateData: []byte{0xbb},
ProofData: []byte{0xcc}, ProofData: []byte{0xcc},
OracleKey: common.Hash{0xdd}.Bytes(),
OracleValue: []byte{0xdd},
OracleOffset: 10,
} }
preimage, proof, data, err := provider.GetStepData(context.Background(), 7000) preimage, proof, data, err := provider.GetStepData(context.Background(), 7000)
require.NoError(t, err) require.NoError(t, err)
require.Contains(t, generator.generated, 10, "should have tried to generate the proof") require.Empty(t, generator.generated, "should not have to generate the proof again")
witness := generator.finalState.EncodeWitness() require.EqualValues(t, initGenerator.finalState.EncodeWitness(), preimage)
require.EqualValues(t, witness, preimage) require.Empty(t, proof)
require.Equal(t, []byte{}, proof)
require.Nil(t, data) require.Nil(t, data)
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment