diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 33278122f..643001866 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -44,7 +44,7 @@ var ( } gasFlag = cli.Float64Flag{ Name: "gas, g", - Usage: "gas to pay for transaction", + Usage: "gas to add to the transaction", } ) @@ -86,8 +86,14 @@ func NewCommands() []cli.Command { }, }, { - Name: "deploy", - Usage: "deploy a smart contract (.avm with description)", + Name: "deploy", + Usage: "deploy a smart contract (.avm with description)", + Description: `Deploys given contract into the chain. The gas parameter is for additional + gas to be added as a network fee to prioritize the transaction. It may also + be required to add that to satisfy chain's policy regarding transaction size + and the minimum size fee (so if transaction send fails, try adding 0.001 GAS + to it). +`, Action: contractDeploy, Flags: []cli.Flag{ cli.StringFlag{ @@ -583,6 +589,8 @@ func contractDeploy(ctx *cli.Context) error { return cli.NewExitError(fmt.Errorf("failed to create deployment script: %v", err), 1) } + gas += smartcontract.GetDeploymentPrice(request.DetailsToSCProperties(&conf.Contract)) + txHash, err := c.SignAndPushInvocationTx(txScript, wif, gas) if err != nil { return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %v", err), 1) diff --git a/pkg/core/gas_price.go b/pkg/core/gas_price.go index 036dc0cbb..021297eb9 100644 --- a/pkg/core/gas_price.go +++ b/pkg/core/gas_price.go @@ -93,18 +93,7 @@ func getSyscallPrice(v *vm.VM, id uint32) util.Fixed8 { arg := estack.Peek(1).BigInt().Int64() return util.Fixed8FromInt64(arg * 5000) case neoContractCreate, neoContractMigrate, antSharesContractCreate, antSharesContractMigrate: - fee := int64(100) - props := smartcontract.PropertyState(estack.Peek(3).BigInt().Int64()) - - if props&smartcontract.HasStorage != 0 { - fee += 400 - } - - if props&smartcontract.HasDynamicInvoke != 0 { - fee += 500 - } - - return util.Fixed8FromInt64(fee) + return smartcontract.GetDeploymentPrice(smartcontract.PropertyState(estack.Peek(3).BigInt().Int64())) case systemStoragePut, systemStoragePutEx, neoStoragePut, antSharesStoragePut: // price for storage PUT is 1 GAS per 1 KiB keySize := len(estack.Peek(1).Bytes()) diff --git a/pkg/rpc/request/txBuilder.go b/pkg/rpc/request/txBuilder.go index 8fe3df81c..f841a71b3 100644 --- a/pkg/rpc/request/txBuilder.go +++ b/pkg/rpc/request/txBuilder.go @@ -80,17 +80,10 @@ func AddInputsAndUnspentsToTx(tx *transaction.Transaction, addr string, assetID return nil } -// CreateDeploymentScript returns a script that deploys given smart contract -// with its metadata. -func CreateDeploymentScript(avm []byte, contract *ContractDetails) ([]byte, error) { +// DetailsToSCProperties extract the fields needed from ContractDetails +// and converts them to smartcontract.PropertyState. +func DetailsToSCProperties(contract *ContractDetails) smartcontract.PropertyState { var props smartcontract.PropertyState - - script := io.NewBufBinWriter() - emit.Bytes(script.BinWriter, []byte(contract.Description)) - emit.Bytes(script.BinWriter, []byte(contract.Email)) - emit.Bytes(script.BinWriter, []byte(contract.Author)) - emit.Bytes(script.BinWriter, []byte(contract.Version)) - emit.Bytes(script.BinWriter, []byte(contract.ProjectName)) if contract.HasStorage { props |= smartcontract.HasStorage } @@ -100,7 +93,19 @@ func CreateDeploymentScript(avm []byte, contract *ContractDetails) ([]byte, erro if contract.IsPayable { props |= smartcontract.IsPayable } - emit.Int(script.BinWriter, int64(props)) + return props +} + +// CreateDeploymentScript returns a script that deploys given smart contract +// with its metadata. +func CreateDeploymentScript(avm []byte, contract *ContractDetails) ([]byte, error) { + script := io.NewBufBinWriter() + emit.Bytes(script.BinWriter, []byte(contract.Description)) + emit.Bytes(script.BinWriter, []byte(contract.Email)) + emit.Bytes(script.BinWriter, []byte(contract.Author)) + emit.Bytes(script.BinWriter, []byte(contract.Version)) + emit.Bytes(script.BinWriter, []byte(contract.ProjectName)) + emit.Int(script.BinWriter, int64(DetailsToSCProperties(contract))) emit.Int(script.BinWriter, int64(contract.ReturnType)) params := make([]byte, len(contract.Parameters)) for k := range contract.Parameters { diff --git a/pkg/smartcontract/deployment_price.go b/pkg/smartcontract/deployment_price.go new file mode 100644 index 000000000..5ba9b8929 --- /dev/null +++ b/pkg/smartcontract/deployment_price.go @@ -0,0 +1,18 @@ +package smartcontract + +import "github.com/nspcc-dev/neo-go/pkg/util" + +// GetDeploymentPrice returns contract deployment price based on its properties. +func GetDeploymentPrice(props PropertyState) util.Fixed8 { + fee := int64(100) + + if props&HasStorage != 0 { + fee += 400 + } + + if props&HasDynamicInvoke != 0 { + fee += 500 + } + + return util.Fixed8FromInt64(fee) +}