Function validateLockSyntax

Validates the Lock script's syntax on its own. For user's safety, Agora's protocol rules disallow accepting an Output with a syntactically invalid Lock script. This prevents accidental loss of funds, for example in cases where the lock script is ill-formed (e.g. missing END blocks, dangling ELSE statements, etc).

string validateLockSyntax (
  in ref const(Lock) lock,
  in const(ulong) StackMaxItemSize
) nothrow @nogc @safe;

The semantics of the lock script are not checked here as it requires an unlock script to run it with. This responsibility lies within the script execution engine.

Parameters

NameDescription
lock the lock to validate
StackMaxItemSize maximum allowed payload size for a stack push operation

Returns

null if the lock is syntactically valid, otherwise the string explaining the reason why it's invalid

Example

import agora.script.Opcodes;
import std.bitmanip;
immutable StackMaxItemSize = 512;

/* LockType.Key */
Lock lock = { type : LockType.Key };
assert(validateLockSyntax(lock, StackMaxItemSize) ==
    "LockType.Key requires 32-byte key argument in the lock script");
lock.bytes.length = Point.sizeof;
assert(validateLockSyntax(lock, StackMaxItemSize) ==
    "LockType.Key 32-byte public key in lock script is invalid");
const rand_key = Scalar.random().toPoint();
lock.bytes = rand_key[];
assert(validateLockSyntax(lock, StackMaxItemSize) == null);

/* LockType.KeyHash */
lock.type = LockType.KeyHash;
lock.bytes.length = 0;
assert(validateLockSyntax(lock, StackMaxItemSize) ==
    "LockType.KeyHash requires a 64-byte key hash argument in the lock script");
lock.bytes.length = Hash.sizeof;  // any 64-byte number is a valid hash
assert(validateLockSyntax(lock, StackMaxItemSize) == null);

/* LockType.Script */
lock.type = LockType.Script;
lock.bytes.length = 0;
assert(validateLockSyntax(lock, StackMaxItemSize) ==
    "Lock script must not be empty");
const ubyte[2] no_overflow = nativeToLittleEndian(
    ushort(StackMaxItemSize));
const ubyte[2] size_overflow = nativeToLittleEndian(
    ushort(StackMaxItemSize + 1));
const ubyte[StackMaxItemSize] max_payload;
lock.bytes = [ubyte(OP.PUSH_DATA_2)] ~ size_overflow ~ max_payload;
assert(validateLockSyntax(lock, StackMaxItemSize) ==
    "PUSH_DATA_2 opcode payload size is not within StackMaxItemSize limits");
lock.bytes = [ubyte(OP.PUSH_DATA_2)] ~ no_overflow ~ max_payload;
assert(validateLockSyntax(lock, StackMaxItemSize) == null);

/* LockType.Redeem */
lock.type = LockType.Redeem;
lock.bytes.length = 0;
assert(validateLockSyntax(lock, StackMaxItemSize) ==
    "LockType.Redeem requires 64-byte script hash in the lock script");
lock.bytes.length = Hash.sizeof;  // any 64-byte number is a valid hash
assert(validateLockSyntax(lock, StackMaxItemSize) == null);