Commit 564b0c17 authored by zhiqiangxu's avatar zhiqiangxu Committed by GitHub

NewChannelBuilder => newChannelBuilder, and move it into channel_builder_test.go (#13148)

parent 25972bd8
...@@ -88,18 +88,6 @@ type ChannelBuilder struct { ...@@ -88,18 +88,6 @@ type ChannelBuilder struct {
outputBytes int outputBytes int
} }
// NewChannelBuilder creates a new channel builder or returns an error if the
// channel out could not be created.
// it acts as a factory for either a span or singular channel out
func NewChannelBuilder(cfg ChannelConfig, rollupCfg *rollup.Config, latestL1OriginBlockNum uint64) (*ChannelBuilder, error) {
co, err := NewChannelOut(cfg, rollupCfg)
if err != nil {
return nil, fmt.Errorf("creating channel out: %w", err)
}
return NewChannelBuilderWithChannelOut(cfg, rollupCfg, latestL1OriginBlockNum, co), nil
}
func NewChannelBuilderWithChannelOut(cfg ChannelConfig, rollupCfg *rollup.Config, latestL1OriginBlockNum uint64, channelOut derive.ChannelOut) *ChannelBuilder { func NewChannelBuilderWithChannelOut(cfg ChannelConfig, rollupCfg *rollup.Config, latestL1OriginBlockNum uint64, channelOut derive.ChannelOut) *ChannelBuilder {
cb := &ChannelBuilder{ cb := &ChannelBuilder{
cfg: cfg, cfg: cfg,
......
...@@ -3,6 +3,7 @@ package batcher ...@@ -3,6 +3,7 @@ package batcher
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt"
"math" "math"
"math/big" "math/big"
"math/rand" "math/rand"
...@@ -27,6 +28,18 @@ var defaultTestRollupConfig = &rollup.Config{ ...@@ -27,6 +28,18 @@ var defaultTestRollupConfig = &rollup.Config{
L2ChainID: big.NewInt(1234), L2ChainID: big.NewInt(1234),
} }
// newChannelBuilder creates a new channel builder or returns an error if the
// channel out could not be created.
// it acts as a factory for either a span or singular channel out
func newChannelBuilder(cfg ChannelConfig, rollupCfg *rollup.Config, latestL1OriginBlockNum uint64) (*ChannelBuilder, error) {
co, err := NewChannelOut(cfg, rollupCfg)
if err != nil {
return nil, fmt.Errorf("creating channel out: %w", err)
}
return NewChannelBuilderWithChannelOut(cfg, rollupCfg, latestL1OriginBlockNum, co), nil
}
// addMiniBlock adds a minimal valid L2 block to the channel builder using the // addMiniBlock adds a minimal valid L2 block to the channel builder using the
// ChannelBuilder.AddBlock method. // ChannelBuilder.AddBlock method.
func addMiniBlock(cb *ChannelBuilder) error { func addMiniBlock(cb *ChannelBuilder) error {
...@@ -106,7 +119,7 @@ func FuzzDurationTimeoutZeroMaxChannelDuration(f *testing.F) { ...@@ -106,7 +119,7 @@ func FuzzDurationTimeoutZeroMaxChannelDuration(f *testing.F) {
f.Fuzz(func(t *testing.T, l1BlockNum uint64) { f.Fuzz(func(t *testing.T, l1BlockNum uint64) {
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
channelConfig.MaxChannelDuration = 0 channelConfig.MaxChannelDuration = 0
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
cb.timeout = 0 cb.timeout = 0
cb.updateDurationTimeout(l1BlockNum) cb.updateDurationTimeout(l1BlockNum)
...@@ -129,7 +142,7 @@ func FuzzChannelBuilder_DurationZero(f *testing.F) { ...@@ -129,7 +142,7 @@ func FuzzChannelBuilder_DurationZero(f *testing.F) {
// Create the channel builder // Create the channel builder
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
channelConfig.MaxChannelDuration = maxChannelDuration channelConfig.MaxChannelDuration = maxChannelDuration
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Whenever the timeout is set to 0, the channel builder should have a duration timeout // Whenever the timeout is set to 0, the channel builder should have a duration timeout
...@@ -156,7 +169,7 @@ func FuzzDurationTimeoutMaxChannelDuration(f *testing.F) { ...@@ -156,7 +169,7 @@ func FuzzDurationTimeoutMaxChannelDuration(f *testing.F) {
// Create the channel builder // Create the channel builder
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
channelConfig.MaxChannelDuration = maxChannelDuration channelConfig.MaxChannelDuration = maxChannelDuration
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Whenever the timeout is greater than the l1BlockNum, // Whenever the timeout is greater than the l1BlockNum,
...@@ -190,7 +203,7 @@ func FuzzChannelCloseTimeout(f *testing.F) { ...@@ -190,7 +203,7 @@ func FuzzChannelCloseTimeout(f *testing.F) {
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
channelConfig.ChannelTimeout = channelTimeout channelConfig.ChannelTimeout = channelTimeout
channelConfig.SubSafetyMargin = subSafetyMargin channelConfig.SubSafetyMargin = subSafetyMargin
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Check the timeout // Check the timeout
...@@ -218,7 +231,7 @@ func FuzzChannelZeroCloseTimeout(f *testing.F) { ...@@ -218,7 +231,7 @@ func FuzzChannelZeroCloseTimeout(f *testing.F) {
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
channelConfig.ChannelTimeout = channelTimeout channelConfig.ChannelTimeout = channelTimeout
channelConfig.SubSafetyMargin = subSafetyMargin channelConfig.SubSafetyMargin = subSafetyMargin
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Check the timeout // Check the timeout
...@@ -245,7 +258,7 @@ func FuzzSeqWindowClose(f *testing.F) { ...@@ -245,7 +258,7 @@ func FuzzSeqWindowClose(f *testing.F) {
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
channelConfig.SeqWindowSize = seqWindowSize channelConfig.SeqWindowSize = seqWindowSize
channelConfig.SubSafetyMargin = subSafetyMargin channelConfig.SubSafetyMargin = subSafetyMargin
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Check the timeout // Check the timeout
...@@ -273,7 +286,7 @@ func FuzzSeqWindowZeroTimeoutClose(f *testing.F) { ...@@ -273,7 +286,7 @@ func FuzzSeqWindowZeroTimeoutClose(f *testing.F) {
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
channelConfig.SeqWindowSize = seqWindowSize channelConfig.SeqWindowSize = seqWindowSize
channelConfig.SubSafetyMargin = subSafetyMargin channelConfig.SubSafetyMargin = subSafetyMargin
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Check the timeout // Check the timeout
...@@ -321,7 +334,7 @@ func TestChannelBuilder_NextFrame(t *testing.T) { ...@@ -321,7 +334,7 @@ func TestChannelBuilder_NextFrame(t *testing.T) {
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
// Create a new channel builder // Create a new channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Mock the internals of `ChannelBuilder.outputFrame` // Mock the internals of `ChannelBuilder.outputFrame`
...@@ -362,7 +375,7 @@ func ChannelBuilder_OutputWrongFramePanic(t *testing.T, batchType uint) { ...@@ -362,7 +375,7 @@ func ChannelBuilder_OutputWrongFramePanic(t *testing.T, batchType uint) {
channelConfig.BatchType = batchType channelConfig.BatchType = batchType
// Construct a channel builder // Construct a channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Mock the internals of `ChannelBuilder.outputFrame` // Mock the internals of `ChannelBuilder.outputFrame`
...@@ -398,7 +411,7 @@ func TestChannelBuilder_OutputFrames(t *testing.T) { ...@@ -398,7 +411,7 @@ func TestChannelBuilder_OutputFrames(t *testing.T) {
channelConfig.InitNoneCompressor() channelConfig.InitNoneCompressor()
// Construct the channel builder // Construct the channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
require.False(t, cb.IsFull()) require.False(t, cb.IsFull())
require.Equal(t, 0, cb.PendingFrames()) require.Equal(t, 0, cb.PendingFrames())
...@@ -452,7 +465,7 @@ func ChannelBuilder_OutputFrames_SpanBatch(t *testing.T, algo derive.Compression ...@@ -452,7 +465,7 @@ func ChannelBuilder_OutputFrames_SpanBatch(t *testing.T, algo derive.Compression
channelConfig.InitRatioCompressor(1, algo) channelConfig.InitRatioCompressor(1, algo)
// Construct the channel builder // Construct the channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
require.False(t, cb.IsFull()) require.False(t, cb.IsFull())
require.Equal(t, 0, cb.PendingFrames()) require.Equal(t, 0, cb.PendingFrames())
...@@ -510,7 +523,7 @@ func ChannelBuilder_MaxRLPBytesPerChannel(t *testing.T, batchType uint) { ...@@ -510,7 +523,7 @@ func ChannelBuilder_MaxRLPBytesPerChannel(t *testing.T, batchType uint) {
channelConfig.BatchType = batchType channelConfig.BatchType = batchType
// Construct the channel builder // Construct the channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Add a block that overflows the [ChannelOut] // Add a block that overflows the [ChannelOut]
...@@ -532,7 +545,7 @@ func ChannelBuilder_MaxRLPBytesPerChannelFjord(t *testing.T, batchType uint) { ...@@ -532,7 +545,7 @@ func ChannelBuilder_MaxRLPBytesPerChannelFjord(t *testing.T, batchType uint) {
channelConfig.BatchType = batchType channelConfig.BatchType = batchType
// Construct the channel builder // Construct the channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Count how many a block that overflows the [ChannelOut] // Count how many a block that overflows the [ChannelOut]
...@@ -553,7 +566,7 @@ func ChannelBuilder_MaxRLPBytesPerChannelFjord(t *testing.T, batchType uint) { ...@@ -553,7 +566,7 @@ func ChannelBuilder_MaxRLPBytesPerChannelFjord(t *testing.T, batchType uint) {
channelConfig.InitNoneCompressor() channelConfig.InitNoneCompressor()
channelConfig.BatchType = batchType channelConfig.BatchType = batchType
cb, err = NewChannelBuilder(channelConfig, rollupConfig, latestL1BlockOrigin) cb, err = newChannelBuilder(channelConfig, rollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// try add double the amount of block, it should not error // try add double the amount of block, it should not error
...@@ -576,7 +589,7 @@ func ChannelBuilder_OutputFramesMaxFrameIndex(t *testing.T, batchType uint) { ...@@ -576,7 +589,7 @@ func ChannelBuilder_OutputFramesMaxFrameIndex(t *testing.T, batchType uint) {
// Continuously add blocks until the max frame index is reached // Continuously add blocks until the max frame index is reached
// This should cause the [ChannelBuilder.OutputFrames] function // This should cause the [ChannelBuilder.OutputFrames] function
// to error // to error
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
require.False(t, cb.IsFull()) require.False(t, cb.IsFull())
require.Equal(t, 0, cb.PendingFrames()) require.Equal(t, 0, cb.PendingFrames())
...@@ -612,7 +625,7 @@ func TestChannelBuilder_FullShadowCompressor(t *testing.T) { ...@@ -612,7 +625,7 @@ func TestChannelBuilder_FullShadowCompressor(t *testing.T) {
} }
cfg.InitShadowCompressor(derive.Zlib) cfg.InitShadowCompressor(derive.Zlib)
cb, err := NewChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(err) require.NoError(err)
rng := rand.New(rand.NewSource(420)) rng := rand.New(rand.NewSource(420))
...@@ -644,7 +657,7 @@ func ChannelBuilder_AddBlock(t *testing.T, batchType uint) { ...@@ -644,7 +657,7 @@ func ChannelBuilder_AddBlock(t *testing.T, batchType uint) {
channelConfig.InitRatioCompressor(1, derive.Zlib) channelConfig.InitRatioCompressor(1, derive.Zlib)
// Construct the channel builder // Construct the channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Add a nonsense block to the channel builder // Add a nonsense block to the channel builder
...@@ -670,7 +683,7 @@ func TestChannelBuilder_CheckTimeout(t *testing.T) { ...@@ -670,7 +683,7 @@ func TestChannelBuilder_CheckTimeout(t *testing.T) {
channelConfig := defaultTestChannelConfig() channelConfig := defaultTestChannelConfig()
// Construct the channel builder // Construct the channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Assert timeout is setup correctly // Assert timeout is setup correctly
...@@ -695,7 +708,7 @@ func TestChannelBuilder_CheckTimeoutZeroMaxChannelDuration(t *testing.T) { ...@@ -695,7 +708,7 @@ func TestChannelBuilder_CheckTimeoutZeroMaxChannelDuration(t *testing.T) {
channelConfig.MaxChannelDuration = 0 channelConfig.MaxChannelDuration = 0
// Construct the channel builder // Construct the channel builder
cb, err := NewChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(channelConfig, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
// Without a max channel duration, timeout should not be set // Without a max channel duration, timeout should not be set
...@@ -718,7 +731,7 @@ func TestChannelBuilder_FramePublished(t *testing.T) { ...@@ -718,7 +731,7 @@ func TestChannelBuilder_FramePublished(t *testing.T) {
cfg.SubSafetyMargin = 100 cfg.SubSafetyMargin = 100
// Construct the channel builder // Construct the channel builder
cb, err := NewChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, latestL1BlockOrigin+cfg.MaxChannelDuration, cb.timeout) require.Equal(t, latestL1BlockOrigin+cfg.MaxChannelDuration, cb.timeout)
...@@ -735,7 +748,7 @@ func TestChannelBuilder_FramePublished(t *testing.T) { ...@@ -735,7 +748,7 @@ func TestChannelBuilder_FramePublished(t *testing.T) {
} }
func TestChannelBuilder_LatestL1Origin(t *testing.T) { func TestChannelBuilder_LatestL1Origin(t *testing.T) {
cb, err := NewChannelBuilder(defaultTestChannelConfig(), defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(defaultTestChannelConfig(), defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, eth.BlockID{}, cb.LatestL1Origin()) require.Equal(t, eth.BlockID{}, cb.LatestL1Origin())
...@@ -757,7 +770,7 @@ func TestChannelBuilder_LatestL1Origin(t *testing.T) { ...@@ -757,7 +770,7 @@ func TestChannelBuilder_LatestL1Origin(t *testing.T) {
} }
func TestChannelBuilder_OldestL1Origin(t *testing.T) { func TestChannelBuilder_OldestL1Origin(t *testing.T) {
cb, err := NewChannelBuilder(defaultTestChannelConfig(), defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(defaultTestChannelConfig(), defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, eth.BlockID{}, cb.OldestL1Origin()) require.Equal(t, eth.BlockID{}, cb.OldestL1Origin())
...@@ -779,7 +792,7 @@ func TestChannelBuilder_OldestL1Origin(t *testing.T) { ...@@ -779,7 +792,7 @@ func TestChannelBuilder_OldestL1Origin(t *testing.T) {
} }
func TestChannelBuilder_LatestL2(t *testing.T) { func TestChannelBuilder_LatestL2(t *testing.T) {
cb, err := NewChannelBuilder(defaultTestChannelConfig(), defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(defaultTestChannelConfig(), defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, eth.BlockID{}, cb.LatestL2()) require.Equal(t, eth.BlockID{}, cb.LatestL2())
...@@ -801,7 +814,7 @@ func TestChannelBuilder_LatestL2(t *testing.T) { ...@@ -801,7 +814,7 @@ func TestChannelBuilder_LatestL2(t *testing.T) {
} }
func TestChannelBuilder_OldestL2(t *testing.T) { func TestChannelBuilder_OldestL2(t *testing.T) {
cb, err := NewChannelBuilder(defaultTestChannelConfig(), defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(defaultTestChannelConfig(), defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, eth.BlockID{}, cb.OldestL2()) require.Equal(t, eth.BlockID{}, cb.OldestL2())
...@@ -831,7 +844,7 @@ func ChannelBuilder_PendingFrames_TotalFrames(t *testing.T, batchType uint) { ...@@ -831,7 +844,7 @@ func ChannelBuilder_PendingFrames_TotalFrames(t *testing.T, batchType uint) {
cfg.TargetNumFrames = tnf cfg.TargetNumFrames = tnf
cfg.BatchType = batchType cfg.BatchType = batchType
cfg.InitShadowCompressor(derive.Zlib) cfg.InitShadowCompressor(derive.Zlib)
cb, err := NewChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(err) require.NoError(err)
// initial builder should be empty // initial builder should be empty
...@@ -876,7 +889,7 @@ func ChannelBuilder_InputBytes(t *testing.T, batchType uint) { ...@@ -876,7 +889,7 @@ func ChannelBuilder_InputBytes(t *testing.T, batchType uint) {
chainId := big.NewInt(1234) chainId := big.NewInt(1234)
spanBatch = derive.NewSpanBatch(uint64(0), chainId) spanBatch = derive.NewSpanBatch(uint64(0), chainId)
} }
cb, err := NewChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(err) require.NoError(err)
require.Zero(cb.InputBytes()) require.Zero(cb.InputBytes())
...@@ -913,7 +926,7 @@ func ChannelBuilder_OutputBytes(t *testing.T, batchType uint) { ...@@ -913,7 +926,7 @@ func ChannelBuilder_OutputBytes(t *testing.T, batchType uint) {
cfg.TargetNumFrames = 16 cfg.TargetNumFrames = 16
cfg.BatchType = batchType cfg.BatchType = batchType
cfg.InitRatioCompressor(1.0, derive.Zlib) cfg.InitRatioCompressor(1.0, derive.Zlib)
cb, err := NewChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin) cb, err := newChannelBuilder(cfg, defaultTestRollupConfig, latestL1BlockOrigin)
require.NoError(err, "NewChannelBuilder") require.NoError(err, "NewChannelBuilder")
require.Zero(cb.OutputBytes()) require.Zero(cb.OutputBytes())
......
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