diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 084474a433..3454574cf1 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -3342,6 +3342,21 @@ func opTxBegin(cx *EvalContext) { } } +// availableAccount is used instead of accountReference for more recent opcodes +// that don't need (or want!) to allow low numbers to represent the account at +// that index in Accounts array. +func (cx *EvalContext) availableAccount(sv stackValue) (basics.Address, error) { + if sv.argType() != StackBytes { + return basics.Address{}, fmt.Errorf("not an address") + } + + addr, _, err := cx.accountReference(sv) + return addr, err +} + +// availableAsset is used instead of asaReference for more recent opcodes that +// don't need (or want!) to allow low numbers to represent the asset at that +// index in ForeignAssets array. func (cx *EvalContext) availableAsset(sv stackValue) (basics.AssetIndex, error) { aid, err := sv.uint() if err != nil { @@ -3366,6 +3381,9 @@ func opTxField(cx *EvalContext) { sv := cx.stack[last] switch field { case Type: + if sv.Bytes == nil { + cx.err = fmt.Errorf("Type arg not a byte array") + } cx.subtxn.Txn.Type = protocol.TxType(sv.Bytes) case TypeEnum: var i uint64 @@ -3375,7 +3393,7 @@ func opTxField(cx *EvalContext) { } case Sender: - cx.subtxn.Txn.Sender, _, cx.err = cx.accountReference(sv) + cx.subtxn.Txn.Sender, cx.err = cx.availableAccount(sv) case Fee: cx.subtxn.Txn.Fee.Raw, cx.err = sv.uint() // FirstValid, LastValid unsettable: no motivation @@ -3388,22 +3406,22 @@ func opTxField(cx *EvalContext) { // KeyReg not allowed yet, so no fields settable case Receiver: - cx.subtxn.Txn.Receiver, _, cx.err = cx.accountReference(sv) + cx.subtxn.Txn.Receiver, cx.err = cx.availableAccount(sv) case Amount: cx.subtxn.Txn.Amount.Raw, cx.err = sv.uint() case CloseRemainderTo: - cx.subtxn.Txn.CloseRemainderTo, _, cx.err = cx.accountReference(sv) + cx.subtxn.Txn.CloseRemainderTo, cx.err = cx.availableAccount(sv) case XferAsset: cx.subtxn.Txn.XferAsset, cx.err = cx.availableAsset(sv) case AssetAmount: cx.subtxn.Txn.AssetAmount, cx.err = sv.uint() case AssetSender: - cx.subtxn.Txn.AssetSender, _, cx.err = cx.accountReference(sv) + cx.subtxn.Txn.AssetSender, cx.err = cx.availableAccount(sv) case AssetReceiver: - cx.subtxn.Txn.AssetReceiver, _, cx.err = cx.accountReference(sv) + cx.subtxn.Txn.AssetReceiver, cx.err = cx.availableAccount(sv) case AssetCloseTo: - cx.subtxn.Txn.AssetCloseTo, _, cx.err = cx.accountReference(sv) + cx.subtxn.Txn.AssetCloseTo, cx.err = cx.availableAccount(sv) // acfg likely next diff --git a/data/transactions/logic/evalAppTxn_test.go b/data/transactions/logic/evalAppTxn_test.go index 24b46a40d2..03001f1962 100644 --- a/data/transactions/logic/evalAppTxn_test.go +++ b/data/transactions/logic/evalAppTxn_test.go @@ -30,6 +30,10 @@ func TestActionTypes(t *testing.T) { testApp(t, "tx_begin; tx_submit; int 1;", ep, "Invalid inner transaction type") // bad type testApp(t, "tx_begin; byte \"pya\"; tx_field Type; tx_submit; int 1;", ep, "Invalid inner transaction type") + // mixed up the int form for the byte form + testApp(t, obfuscate("tx_begin; int pay; tx_field Type; tx_submit; int 1;"), ep, "Type arg not a byte array") + // or vice versa + testApp(t, obfuscate("tx_begin; byte \"pay\"; tx_field TypeEnum; tx_submit; int 1;"), ep, "not a uint64") // good types, not alllowed yet testApp(t, "tx_begin; byte \"keyreg\"; tx_field Type; tx_submit; int 1;", ep, "Invalid inner transaction type") @@ -57,6 +61,26 @@ func TestActionTypes(t *testing.T) { testApp(t, "tx_begin; int pay; tx_field TypeEnum; tx_submit; int 1;", ep) } +func TestFieldTypes(t *testing.T) { + ep, _ := makeSampleEnv() + testApp(t, "tx_begin; byte \"pay\"; tx_field Sender;", ep, "not an address") + testApp(t, obfuscate("tx_begin; int 7; tx_field Receiver;"), ep, "not an address") + testApp(t, "tx_begin; byte \"\"; tx_field CloseRemainderTo;", ep, "not an address") + testApp(t, "tx_begin; byte \"\"; tx_field AssetSender;", ep, "not an address") + // can't really tell if it's an addres, so 32 bytes gets further + testApp(t, "tx_begin; byte \"01234567890123456789012345678901\"; tx_field AssetReceiver;", + ep, "invalid Account reference") + // but a b32 string rep is not an account + testApp(t, "tx_begin; byte \"GAYTEMZUGU3DOOBZGAYTEMZUGU3DOOBZGAYTEMZUGU3DOOBZGAYZIZD42E\"; tx_field AssetCloseTo;", + ep, "not an address") + + testApp(t, obfuscate("tx_begin; byte \"pay\"; tx_field Fee;"), ep, "not a uint64") + testApp(t, obfuscate("tx_begin; byte 0x01; tx_field Amount;"), ep, "not a uint64") + testApp(t, obfuscate("tx_begin; byte 0x01; tx_field XferAsset;"), ep, "not a uint64") + testApp(t, obfuscate("tx_begin; byte 0x01; tx_field AssetAmount;"), ep, "not a uint64") + +} + func TestAppPay(t *testing.T) { pay := ` tx_begin diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index f9f0bea344..573f709945 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -4573,17 +4573,21 @@ func TestShifts(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() + testAccepts(t, "int 1; int 0; shl; int 1; ==", 4) testAccepts(t, "int 1; int 1; shl; int 2; ==", 4) testAccepts(t, "int 1; int 2; shl; int 4; ==", 4) testAccepts(t, "int 3; int 2; shl; int 12; ==", 4) testAccepts(t, "int 2; int 63; shl; int 0; ==", 4) + testAccepts(t, "int 3; int 0; shr; int 3; ==", 4) testAccepts(t, "int 1; int 1; shr; int 0; ==", 4) testAccepts(t, "int 1; int 2; shr; int 0; ==", 4) testAccepts(t, "int 3; int 1; shr; int 1; ==", 4) testAccepts(t, "int 96; int 3; shr; int 12; ==", 4) testAccepts(t, "int 8756675; int 63; shr; int 0; ==", 4) + testPanics(t, "int 8756675; int 64; shr; int 0; ==", 4) + testPanics(t, "int 8756675; int 64; shl; int 0; ==", 4) } func TestSqrt(t *testing.T) { @@ -4623,6 +4627,10 @@ func TestExp(t *testing.T) { testAccepts(t, "int 3; int 1; exp; int 3; ==", 4) testAccepts(t, "int 96; int 3; exp; int 884736; ==", 4) testPanics(t, "int 96; int 15; exp; int 884736; >", 4) + + // These seem the same but check different code paths + testPanics(t, "int 2; int 64; exp; pop; int 1", 4) + testPanics(t, "int 4; int 32; exp; pop; int 1", 4) } func TestExpw(t *testing.T) { @@ -4639,6 +4647,10 @@ func TestExpw(t *testing.T) { testPanics(t, "int 64; int 22; expw; pop; pop; int 1", 4) // (2^6)^22 = 2^132 testAccepts(t, "int 97; int 15; expw; int 10271255586529954209; ==; assert; int 34328615749; ==;", 4) + + testPanics(t, "int 2; int 128; expw; pop; pop; int 1", 4) // 2^128 is too big + // looks the same, but different code path + testPanics(t, "int 4; int 64; expw; pop; pop; int 1", 4) // 2^128 is too big } func TestBitLen(t *testing.T) { @@ -4744,6 +4756,9 @@ func TestBytesBits(t *testing.T) { testAccepts(t, "int 3; bzero; byte 0x000000; ==", 4) testAccepts(t, "int 33; bzero; byte 0x000000000000000000000000000000000000000000000000000000000000000000; ==", 4) + + testAccepts(t, "int 4096; bzero; len; int 4096; ==", 4) + testPanics(t, "int 4097; bzero; len; int 4097; ==", 4) } func TestBytesConversions(t *testing.T) {