forked from TrueCloudLab/frostfs-node
[#822] event/notaryPreparator: Do not pass PACK
opcode
Do not pass high level `PACK` opcode to notary parsers. Add opcode amount check. Delete `PACK` cases in notary parsers. Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
4f3de1a9af
commit
3b9ef4f63c
4 changed files with 70 additions and 21 deletions
|
@ -57,8 +57,6 @@ func ParseDeleteNotary(ne event.NotaryEvent) (event.Event, error) {
|
||||||
|
|
||||||
deleteFieldSetters[fieldNum](&ev, op.Param())
|
deleteFieldSetters[fieldNum](&ev, op.Param())
|
||||||
fieldNum++
|
fieldNum++
|
||||||
case opcode.PUSH0 <= currentOp && currentOp <= opcode.PUSH16 || currentOp == opcode.PACK:
|
|
||||||
// array packing opcodes. do nothing with it
|
|
||||||
default:
|
default:
|
||||||
return nil, event.UnexpectedOpcode(DeleteNotaryEvent, op.Code())
|
return nil, event.UnexpectedOpcode(DeleteNotaryEvent, op.Code())
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,6 @@ func ParseSetEACLNotary(ne event.NotaryEvent) (event.Event, error) {
|
||||||
|
|
||||||
setEACLFieldSetters[fieldNum](&ev, op.Param())
|
setEACLFieldSetters[fieldNum](&ev, op.Param())
|
||||||
fieldNum++
|
fieldNum++
|
||||||
case opcode.PUSH0 <= currentOp && currentOp <= opcode.PUSH16 || currentOp == opcode.PACK:
|
|
||||||
// array packing opcodes. do nothing with it
|
|
||||||
default:
|
default:
|
||||||
return nil, event.UnexpectedOpcode(SetEACLNotaryEvent, op.Code())
|
return nil, event.UnexpectedOpcode(SetEACLNotaryEvent, op.Code())
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,6 @@ func ParsePutNotary(ne event.NotaryEvent) (event.Event, error) {
|
||||||
|
|
||||||
putFieldSetters[fieldNum](&ev, op.Param())
|
putFieldSetters[fieldNum](&ev, op.Param())
|
||||||
fieldNum++
|
fieldNum++
|
||||||
case opcode.PUSH0 <= currentOp && currentOp <= opcode.PUSH16 || currentOp == opcode.PACK:
|
|
||||||
// array packing opcodes. do nothing with it
|
|
||||||
default:
|
default:
|
||||||
return nil, event.UnexpectedOpcode(PutNotaryEvent, op.Code())
|
return nil, event.UnexpectedOpcode(PutNotaryEvent, op.Code())
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,9 @@ var (
|
||||||
errIncorrectNotaryPlaceholder = errors.New("received main tx has incorrect Notary contract placeholder")
|
errIncorrectNotaryPlaceholder = errors.New("received main tx has incorrect Notary contract placeholder")
|
||||||
errIncorrectAttributesAmount = errors.New("received main tx has incorrect attributes amount")
|
errIncorrectAttributesAmount = errors.New("received main tx has incorrect attributes amount")
|
||||||
errIncorrectAttribute = errors.New("received main tx has incorrect attribute")
|
errIncorrectAttribute = errors.New("received main tx has incorrect attribute")
|
||||||
errUnexpectedOpcode = errors.New("received main tx has unexpected(not PUSH) NeoVM opcodes")
|
|
||||||
errIncorrectCallFlag = errors.New("received main tx has unexpected call flag")
|
errIncorrectCallFlag = errors.New("received main tx has unexpected call flag")
|
||||||
|
errIncorrectArgPacking = errors.New("received main tx has incorrect argument packing")
|
||||||
|
errUnexpectedCONVERT = errors.New("received main tx has unexpected CONVERT opcode")
|
||||||
|
|
||||||
errIncorrectFBAttributesAmount = errors.New("received fallback tx has incorrect attributes amount")
|
errIncorrectFBAttributesAmount = errors.New("received fallback tx has incorrect attributes amount")
|
||||||
errIncorrectFBAttributes = errors.New("received fallback tx has incorrect attributes")
|
errIncorrectFBAttributes = errors.New("received fallback tx has incorrect attributes")
|
||||||
|
@ -154,7 +155,7 @@ func (p Preparator) Prepare(nr *payload.P2PNotaryRequest) (NotaryEvent, error) {
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx := vm.NewContext(nr.MainTransaction.Script)
|
ctx := vm.NewContext(nr.MainTransaction.Script)
|
||||||
ops := make([]Op, 0, 16) // 16 is maximum num of opcodes for calling contracts with 4 args(no arrays of arrays)
|
ops := make([]Op, 0, 10) // 10 is maximum num of opcodes for calling contracts with 4 args(no arrays of arrays)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
opCode, param, err = ctx.Next()
|
opCode, param, err = ctx.Next()
|
||||||
|
@ -191,31 +192,85 @@ func (p Preparator) Prepare(nr *payload.P2PNotaryRequest) (NotaryEvent, error) {
|
||||||
return nil, errIncorrectCallFlag
|
return nil, errIncorrectCallFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p.validateParameterOpcodes(ops[:opsLen-4])
|
args := ops[:opsLen-4]
|
||||||
|
|
||||||
|
if len(args) != 0 {
|
||||||
|
err = p.validateParameterOpcodes(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("could not validate arguments: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// without args packing opcodes
|
||||||
|
args = args[:len(args)-2]
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedNotaryEvent{
|
return parsedNotaryEvent{
|
||||||
hash: contractHash,
|
hash: contractHash,
|
||||||
notaryType: NotaryTypeFromString(contractMethod),
|
notaryType: NotaryTypeFromString(contractMethod),
|
||||||
params: ops[:opsLen-4],
|
params: args,
|
||||||
raw: nr,
|
raw: nr,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Preparator) validateParameterOpcodes(oo []Op) error {
|
func (p Preparator) validateParameterOpcodes(ops []Op) error {
|
||||||
// check for unexpected NeoVM opcodes
|
l := len(ops)
|
||||||
for _, o := range oo {
|
|
||||||
switch {
|
if ops[l-1].code != opcode.PACK {
|
||||||
// only PUSH(and PACK for arrays) codes are allowed;
|
return fmt.Errorf("unexpected packing opcode: %s", ops[l-1].code)
|
||||||
// number of params and their content must be checked
|
|
||||||
// in a notary parser and a notary handler of a
|
|
||||||
// particular contract
|
|
||||||
case o.code <= opcode.PUSH16 || o.code == opcode.PACK:
|
|
||||||
default:
|
|
||||||
return errUnexpectedOpcode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
argsLen, err := IntFromOpcode(ops[l-2])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse argument len: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validateNestedArgs(argsLen, ops[:l-2])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateNestedArgs(expArgLen int64, ops []Op) error {
|
||||||
|
var (
|
||||||
|
currentCode opcode.Opcode
|
||||||
|
|
||||||
|
opsLenGot = len(ops)
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := opsLenGot - 1; i >= 0; i-- {
|
||||||
|
// only PUSH(also, PACK for arrays and CONVERT for booleans)
|
||||||
|
// codes are allowed; number of params and their content must
|
||||||
|
// be checked in a notary parser and a notary handler of a
|
||||||
|
// particular contract
|
||||||
|
switch currentCode = ops[i].code; {
|
||||||
|
case currentCode <= opcode.PUSH16:
|
||||||
|
case currentCode == opcode.CONVERT:
|
||||||
|
if i == 0 || ops[i-1].code != opcode.PUSHT && ops[i-1].code != opcode.PUSHF {
|
||||||
|
return errUnexpectedCONVERT
|
||||||
|
}
|
||||||
|
|
||||||
|
expArgLen++
|
||||||
|
case currentCode == opcode.PACK:
|
||||||
|
if i == 0 {
|
||||||
|
return errIncorrectArgPacking
|
||||||
|
}
|
||||||
|
|
||||||
|
argsLen, err := IntFromOpcode(ops[i-1])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse argument len: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expArgLen += argsLen + 1
|
||||||
|
i--
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("received main tx has unexpected(not PUSH) NeoVM opcode: %s", currentCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if int64(opsLenGot) != expArgLen {
|
||||||
|
return errIncorrectArgPacking
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in a new issue