Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions pkg/arkade/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,38 @@ func TestNewOpcodes(t *testing.T) {
},
},
},
{
// OP_CAT must enforce the per-element size limit
// (MaxScriptElementSize == 520 bytes) on its result. Repeatedly
// duplicating and concatenating doubles the element size each
// round; without the limit this is an exponential-growth DoS.
// Starting from a 200-byte element: 200 -> 400 -> 800, so the
// second OP_CAT must fail.
name: "OP_CAT_growth_limit",
script: txscript.NewScriptBuilder().
AddOp(OP_DUP).AddOp(OP_CAT). // 200 -> 400
AddOp(OP_DUP).AddOp(OP_CAT), // 400 -> 800 (must fail)
cases: []testCase{
{
valid: false,
tx: &wire.MsgTx{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 0,
},
},
},
},
txIdx: 0,
inputAmount: 0,
stack: [][]byte{bytes.Repeat([]byte{0x01}, 200)},
errText: "exceeds max allowed size",
},
},
},
{
name: "OP_DIV",
script: txscript.NewScriptBuilder().AddOp(OP_DIV).AddOp(OP_3).AddOp(OP_EQUAL),
Expand Down
6 changes: 6 additions & 0 deletions pkg/arkade/opcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,12 @@ func opcodeCat(op *opcode, data []byte, vm *Engine) error {
return err
}

if len(x1)+len(x2) > txscript.MaxScriptElementSize {
str := fmt.Sprintf("concatenated size %d exceeds max allowed size %d",
len(x1)+len(x2), txscript.MaxScriptElementSize)
return scriptError(txscript.ErrElementTooBig, str)
}

vm.dstack.PushByteArray(append(x1, x2...))
return nil
}
Expand Down
24 changes: 24 additions & 0 deletions pkg/arkade/opcode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1342,13 +1342,36 @@ func catSpec() *opcodeSpec {
inputStack: [][]byte{{0x01}, {0x02}},
expectedStack: [][]byte{{0x01, 0x02}},
},
{
// Concatenating to exactly MaxScriptElementSize (520) is
// allowed; only results strictly larger are rejected.
name: "result_at_max_element_size",
inputStack: [][]byte{
bytes.Repeat([]byte{0x01}, 260),
bytes.Repeat([]byte{0x02}, 260),
},
expectedStack: [][]byte{
append(bytes.Repeat([]byte{0x01}, 260), bytes.Repeat([]byte{0x02}, 260)...),
},
},
},
invalidVectors: []opcodeVector{
{
name: "underflow",
inputStack: [][]byte{{0x01}},
expectedError: txscript.ErrInvalidStackOperation,
},
{
// Two individually valid (<=520 byte) operands whose
// concatenation exceeds MaxScriptElementSize (520) must
// fail rather than produce an oversized stack element.
name: "result_exceeds_max_element_size",
inputStack: [][]byte{
bytes.Repeat([]byte{0x01}, 300),
bytes.Repeat([]byte{0x02}, 300),
},
expectedError: txscript.ErrElementTooBig,
},
},
}
}
Expand Down Expand Up @@ -1492,6 +1515,7 @@ func byteTransformPropertyChecker(op byte) opcodePropertyChecker {
txscript.ErrInvalidIndex,
txscript.ErrNumberTooBig,
txscript.ErrMinimalData,
txscript.ErrElementTooBig,
)
require.LessOrEqual(t, afterDepth, beforeDepth)
return
Expand Down
Loading