Skip to content

Commit 579e1b4

Browse files
authored
Merge pull request #4358 from onflow/bastian/fix-compiler-contract-deployment-transfer
[Compiler] Fix transfer during contract deployment with arguments
2 parents d0a7985 + d45e1e8 commit 579e1b4

3 files changed

Lines changed: 147 additions & 18 deletions

File tree

runtime/deployment_test.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ import (
2424
"strings"
2525
"testing"
2626

27+
"github.com/onflow/atree"
2728
"github.com/stretchr/testify/assert"
2829
"github.com/stretchr/testify/require"
2930
"golang.org/x/crypto/sha3"
3031

3132
"github.com/onflow/cadence"
33+
"github.com/onflow/cadence/bbq/vm"
3234
"github.com/onflow/cadence/common"
3335
"github.com/onflow/cadence/interpreter"
3436
. "github.com/onflow/cadence/runtime"
@@ -365,3 +367,136 @@ func TestRuntimeTransactionWithContractDeployment(t *testing.T) {
365367
})
366368
})
367369
}
370+
371+
func TestRuntimeContractDeploymentInitializerArgument(t *testing.T) {
372+
373+
t.Parallel()
374+
375+
runtime := NewTestRuntime()
376+
377+
addressValue := cadence.BytesToAddress([]byte{0xCA, 0xDE})
378+
379+
contract := []byte(`
380+
access(all) contract Test {
381+
init(arg: {Int: Int}) {
382+
check(arg)
383+
}
384+
}
385+
`)
386+
387+
deploy := fmt.Sprintf(
388+
`
389+
transaction {
390+
prepare(signer: auth(Contracts) &Account) {
391+
let arg: {Int: Int} = {}
392+
signer.contracts.add(name: "Test", code: "%s".decodeHex(), arg: arg)
393+
}
394+
}
395+
`,
396+
hex.EncodeToString(contract),
397+
)
398+
399+
var accountCode []byte
400+
401+
runtimeInterface := &TestRuntimeInterface{
402+
OnGetCode: func(_ Location) (bytes []byte, err error) {
403+
return accountCode, nil
404+
},
405+
Storage: NewTestLedger(nil, nil),
406+
OnGetSigningAccounts: func() ([]Address, error) {
407+
return []Address{Address(addressValue)}, nil
408+
},
409+
OnGetAccountContractCode: func(_ common.AddressLocation) (code []byte, err error) {
410+
return accountCode, nil
411+
},
412+
OnUpdateAccountContractCode: func(_ common.AddressLocation, code []byte) error {
413+
accountCode = code
414+
return nil
415+
},
416+
OnEmitEvent: func(event cadence.Event) error {
417+
return nil
418+
},
419+
}
420+
421+
check := func(value interpreter.Value) {
422+
dictionaryValue, ok := value.(*interpreter.DictionaryValue)
423+
require.True(t, ok)
424+
425+
assert.Equal(t,
426+
atree.ValueID{
427+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
428+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6,
429+
},
430+
dictionaryValue.ValueID(),
431+
)
432+
}
433+
434+
transactionEnvironment := newTransactionEnvironment()
435+
436+
functionType := sema.NewSimpleFunctionType(
437+
sema.FunctionPurityView,
438+
[]sema.Parameter{
439+
{
440+
Label: sema.ArgumentLabelNotRequired,
441+
Identifier: "arg",
442+
TypeAnnotation: sema.NewTypeAnnotation(
443+
sema.NewDictionaryType(nil, sema.IntType, sema.IntType),
444+
),
445+
},
446+
},
447+
sema.VoidTypeAnnotation,
448+
)
449+
450+
var function interpreter.FunctionValue
451+
452+
const functionName = "check"
453+
if *compile {
454+
function = vm.NewNativeFunctionValue(
455+
functionName,
456+
functionType,
457+
func(
458+
_ interpreter.NativeFunctionContext,
459+
_ interpreter.TypeArgumentsIterator,
460+
_ interpreter.Value,
461+
args []interpreter.Value,
462+
) interpreter.Value {
463+
check(args[0])
464+
return interpreter.Void
465+
},
466+
)
467+
} else {
468+
function = interpreter.NewStaticHostFunctionValue(
469+
nil,
470+
functionType,
471+
func(invocation interpreter.Invocation) interpreter.Value {
472+
check(invocation.Arguments[0])
473+
return interpreter.Void
474+
},
475+
)
476+
}
477+
478+
transactionEnvironment.DeclareValue(
479+
stdlib.StandardLibraryValue{
480+
Name: functionName,
481+
Type: functionType,
482+
Kind: common.DeclarationKindFunction,
483+
Value: function,
484+
},
485+
nil,
486+
)
487+
488+
nextTransactionLocation := NewTransactionLocationGenerator()
489+
490+
err := runtime.ExecuteTransaction(
491+
Script{
492+
Source: []byte(deploy),
493+
},
494+
Context{
495+
Interface: runtimeInterface,
496+
Environment: transactionEnvironment,
497+
Location: nextTransactionLocation(),
498+
UseVM: *compile,
499+
},
500+
)
501+
require.NoError(t, err)
502+
}

runtime/environment.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,13 +372,11 @@ func (e *InterpreterEnvironment) newContractValueHandler() interpreter.ContractV
372372

373373
constructor := constructorGenerator(invocation.Address)
374374

375-
value, err := interpreter.InvokeFunctionValue(
375+
value, err := interpreter.InvokeExternally(
376376
inter,
377377
constructor,
378+
constructor.FunctionType(inter),
378379
invocation.ConstructorArguments,
379-
invocation.ArgumentTypes,
380-
invocation.ParameterTypes,
381-
invocation.ContractType,
382380
)
383381
if err != nil {
384382
panic(err)

stdlib/account.go

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,8 +2311,6 @@ func updateAccountContractCode(
23112311
type DeployedContractConstructorInvocation struct {
23122312
ContractType *sema.CompositeType
23132313
ConstructorArguments []interpreter.Value
2314-
ArgumentTypes []sema.Type
2315-
ParameterTypes []sema.Type
23162314
Address common.Address
23172315
}
23182316

@@ -2348,22 +2346,20 @@ func instantiateContract(
23482346
constructorArguments []interpreter.Value,
23492347
argumentTypes []sema.Type,
23502348
) (*interpreter.CompositeValue, error) {
2351-
parameterTypes := make([]sema.Type, len(contractType.ConstructorParameters))
2352-
2353-
for i, constructorParameter := range contractType.ConstructorParameters {
2354-
parameterTypes[i] = constructorParameter.TypeAnnotation.Type
2355-
}
23562349

23572350
// Check argument count
23582351

2352+
constructorParameters := contractType.ConstructorParameters
2353+
23592354
argumentCount := len(argumentTypes)
2360-
parameterCount := len(parameterTypes)
2355+
parameterCount := len(constructorParameters)
23612356

23622357
if argumentCount < parameterCount {
2358+
parameter := constructorParameters[argumentCount]
23632359
return nil, errors.NewDefaultUserError(
23642360
"invalid argument count, too few arguments: expected %d, got %d, next missing argument: `%s`",
23652361
parameterCount, argumentCount,
2366-
parameterTypes[argumentCount],
2362+
parameter.TypeAnnotation.Type,
23672363
)
23682364
} else if argumentCount > parameterCount {
23692365
return nil, errors.NewDefaultUserError(
@@ -2379,12 +2375,14 @@ func instantiateContract(
23792375

23802376
for argumentIndex := 0; argumentIndex < argumentCount; argumentIndex++ {
23812377
argumentType := argumentTypes[argumentIndex]
2382-
parameterTye := parameterTypes[argumentIndex]
2383-
if !sema.IsSubType(argumentType, parameterTye) {
2378+
parameter := constructorParameters[argumentIndex]
2379+
parameterType := parameter.TypeAnnotation.Type
2380+
2381+
if !sema.IsSubType(argumentType, parameterType) {
23842382

23852383
return nil, &InvalidContractArgumentError{
23862384
Index: argumentIndex,
2387-
ExpectedType: parameterTye,
2385+
ExpectedType: parameterType,
23882386
ActualType: argumentType,
23892387
}
23902388
}
@@ -2406,8 +2404,6 @@ func instantiateContract(
24062404
Address: location.Address,
24072405
ContractType: contractType,
24082406
ConstructorArguments: constructorArguments,
2409-
ArgumentTypes: argumentTypes,
2410-
ParameterTypes: parameterTypes,
24112407
},
24122408
)
24132409
}

0 commit comments

Comments
 (0)