Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions cmd/rofl/common/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ var (
// NoUpdateFlag is the flag for disabling the rofl.yaml manifest file update.
NoUpdateFlag *flag.FlagSet

// TermFlags provide the term and count setting.
TermFlags *flag.FlagSet

// DeploymentName is the name of the ROFL app deployment.
DeploymentName string

Expand All @@ -24,6 +27,12 @@ var (

// NoUpdate disables updating the rofl.yaml manifest file.
NoUpdate bool

// Term specifies the rental base unit.
Term string

// TermCount specific the rental base unit multiplier.
TermCount uint64
)

func init() {
Expand All @@ -35,4 +44,8 @@ func init() {

NoUpdateFlag = flag.NewFlagSet("", flag.ContinueOnError)
NoUpdateFlag.BoolVar(&NoUpdate, "no-update-manifest", false, "do not update the manifest")

TermFlags = flag.NewFlagSet("", flag.ContinueOnError)
TermFlags.StringVar(&Term, "term", "", "term to pay for in advance [hour, month, year]")
TermFlags.Uint64Var(&TermCount, "term-count", 1, "number of terms to pay for in advance")
}
56 changes: 30 additions & 26 deletions cmd/rofl/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ var (
deployProvider string
deployOffer string
deployMachine string
deployTerm string
deployTermCount uint64
deployForce bool
deployShowOffers bool
deployReplaceMachine bool
Expand Down Expand Up @@ -150,7 +148,7 @@ var (
},
}

obtainMachine := func() (*buildRofl.Machine, error) {
obtainMachine := func() (*buildRofl.Machine, *roflmarket.Instance, error) {
if deployOffer != "" {
machine.Offer = deployOffer
}
Expand All @@ -168,19 +166,19 @@ var (
}
if offer == nil {
showProviderOffers(ctx, npa, conn, *providerAddr)
return nil, fmt.Errorf("offer '%s' not found for provider '%s'", machine.Offer, providerAddr)
return nil, nil, fmt.Errorf("offer '%s' not found for provider '%s'", machine.Offer, providerAddr)
}

fmt.Printf("Taking offer:\n")
showProviderOffer(ctx, offer)

term := detectTerm(offer)
if deployTermCount < 1 {
return nil, fmt.Errorf("number of terms must be at least 1")
if roflCommon.TermCount < 1 {
return nil, nil, fmt.Errorf("number of terms must be at least 1")
}

// Calculate total price.
qTermCount := quantity.NewFromUint64(deployTermCount)
qTermCount := quantity.NewFromUint64(roflCommon.TermCount)
totalPrice, ok := offer.Payment.Native.Terms[term]
if !ok {
cobra.CheckErr("internal error: previously selected term not found in offer terms")
Expand All @@ -197,7 +195,7 @@ var (
Offer: offer.ID,
Deployment: &machineDeployment,
Term: term,
TermCount: deployTermCount,
TermCount: roflCommon.TermCount,
})

var sigTx, meta any
Expand All @@ -206,23 +204,27 @@ var (

var machineID roflmarket.InstanceID
if !common.BroadcastOrExportTransaction(ctx, npa, conn, sigTx, meta, &machineID) {
return nil, fmt.Errorf("broadcast transaction failed")
return nil, nil, fmt.Errorf("broadcast transaction failed")
}

rawMachineID, _ := machineID.MarshalText()
cobra.CheckErr(err)
machine.ID = string(rawMachineID)
deployment.Machines[deployMachine] = machine

fmt.Printf("Created machine: %s\n", machine.ID)
return machine, nil

var insDsc *roflmarket.Instance
insDsc, err = conn.Runtime(npa.ParaTime).ROFLMarket.Instance(ctx, client.RoundLatest, *providerAddr, machineID)
cobra.CheckErr(err)

return machine, insDsc, nil
}

doDeployMachine := func(machine *buildRofl.Machine) error {
doDeployMachine := func(machine *buildRofl.Machine) (*roflmarket.Instance, error) {
// Deploy into existing machine.
var machineID roflmarket.InstanceID
if err = machineID.UnmarshalText([]byte(machine.ID)); err != nil {
return fmt.Errorf("malformed machine ID: %w", err)
return nil, fmt.Errorf("malformed machine ID: %w", err)
}

fmt.Printf("Deploying into existing machine: %s\n", machine.ID)
Expand All @@ -237,8 +239,8 @@ var (
if deployReplaceMachine {
fmt.Printf("Machine instance not found. Obtaining new one...")
machine.ID = ""
_, err = obtainMachine()
return err
_, _, err = obtainMachine()
return nil, err
}

cobra.CheckErr("Machine instance not found.\nTip: If your instance expired, run this command with --replace-machine flag to replace it with a new machine.")
Expand All @@ -248,7 +250,7 @@ var (
if insDsc.Deployment != nil && insDsc.Deployment.AppID != machineDeployment.AppID && !deployForce {
fmt.Printf("Machine already contains a deployment of ROFL app '%s'.\n", insDsc.Deployment.AppID)
fmt.Printf("You are trying to replace it with ROFL app '%s'.\n", machineDeployment.AppID)
return fmt.Errorf("refusing to change existing ROFL app, use --force to override")
return nil, fmt.Errorf("refusing to change existing ROFL app, use --force to override")
}

// Prepare transaction.
Expand All @@ -269,23 +271,26 @@ var (
cobra.CheckErr(err)

if !common.BroadcastOrExportTransaction(ctx, npa, conn, sigTx, meta, nil) {
return fmt.Errorf("broadcast transaction failed")
return nil, fmt.Errorf("broadcast transaction failed")
}

return nil
return insDsc, nil
}

var insDsc *roflmarket.Instance
if machine.ID == "" {
// When machine is not set, we need to obtain one.
fmt.Printf("No pre-existing machine configured, creating a new one...\n")
machine, err = obtainMachine()
machine, insDsc, err = obtainMachine()
cobra.CheckErr(err)
} else {
cobra.CheckErr(doDeployMachine(machine))
insDsc, err = doDeployMachine(machine)
cobra.CheckErr(err)
}

fmt.Printf("Deployment into machine scheduled.\n")
fmt.Printf("Use `oasis rofl machine show` to see status.\n")
fmt.Printf("This machine expires on %s. Use `oasis rofl machine top-up` to extend it.\n", time.Unix(int64(insDsc.PaidUntil), 0))
fmt.Printf("Use `oasis rofl machine show` to check status.\n")

if err = manifest.Save(); err != nil {
cobra.CheckErr(fmt.Errorf("failed to update manifest: %w", err))
Expand Down Expand Up @@ -327,11 +332,11 @@ func detectTerm(offer *roflmarket.Offer) (term roflmarket.Term) {
cobra.CheckErr(fmt.Errorf("no payment terms available for offer '%s'", offer.ID))
}

if deployTerm != "" {
if roflCommon.Term != "" {
// Custom deploy term.
term = roflCommon.ParseMachineTerm(deployTerm)
term = roflCommon.ParseMachineTerm(roflCommon.Term)
if _, ok := offer.Payment.Native.Terms[term]; !ok {
cobra.CheckErr(fmt.Errorf("term '%s' is not available for offer '%s'", deployTerm, offer.ID))
cobra.CheckErr(fmt.Errorf("term '%s' is not available for offer '%s'", roflCommon.Term, offer.ID))
}
return
}
Expand Down Expand Up @@ -447,8 +452,6 @@ func init() {
providerFlags.StringVar(&deployProvider, "provider", "", "set the provider address")
providerFlags.StringVar(&deployOffer, "offer", "", "set the provider's offer identifier")
providerFlags.StringVar(&deployMachine, "machine", buildRofl.DefaultMachineName, "machine to deploy into")
providerFlags.StringVar(&deployTerm, "term", "", "term to pay for in advance")
providerFlags.Uint64Var(&deployTermCount, "term-count", 1, "number of terms to pay for in advance")
providerFlags.BoolVar(&deployForce, "force", false, "force deployment")
providerFlags.BoolVar(&deployShowOffers, "show-offers", false, "show all provider offers and quit")
providerFlags.BoolVar(&deployReplaceMachine, "replace-machine", false, "rent a new machine if the provided one expired")
Expand All @@ -457,4 +460,5 @@ func init() {
deployCmd.Flags().AddFlagSet(providerFlags)
deployCmd.Flags().AddFlagSet(roflCommon.DeploymentFlags)
deployCmd.Flags().AddFlagSet(roflCommon.WipeFlags)
deployCmd.Flags().AddFlagSet(roflCommon.TermFlags)
}
25 changes: 10 additions & 15 deletions cmd/rofl/machine/mgmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"time"

"github.com/spf13/cobra"
flag "github.com/spf13/pflag"

"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/client"
Expand All @@ -22,9 +21,6 @@ import (
)

var (
topUpTerm string
topUpTermCount uint64

showCmd = &cobra.Command{
Use: "show [<machine-name>]",
Short: "Show information about a machine",
Expand Down Expand Up @@ -262,13 +258,16 @@ var (
// Resolve provider address.
providerAddr, _, err := common.ResolveLocalAccountOrAddress(npa.Network, machine.Provider)
if err != nil {
cobra.CheckErr(fmt.Sprintf("Invalid provider address: %s", err))
cobra.CheckErr(fmt.Sprintf("invalid provider address: %s", err))
}

// Parse machine payment term.
term := roflCommon.ParseMachineTerm(topUpTerm)
if topUpTermCount < 1 {
cobra.CheckErr("Number of terms must be at least 1.")
if roflCommon.Term == "" {
cobra.CheckErr("no term period specified. Use --term to specify it")
}
term := roflCommon.ParseMachineTerm(roflCommon.Term)
if roflCommon.TermCount < 1 {
cobra.CheckErr("number of terms must be at least 1.")
}

// When not in offline mode, connect to the given network endpoint.
Expand All @@ -281,14 +280,14 @@ var (

fmt.Printf("Using provider: %s (%s)\n", machine.Provider, providerAddr)
fmt.Printf("Top-up machine: %s [%s]\n", machineName, machine.ID)
fmt.Printf("Top-up term: %d x %s\n", topUpTermCount, topUpTerm)
fmt.Printf("Top-up term: %d x %s\n", roflCommon.TermCount, roflCommon.Term)

// Prepare transaction.
tx := roflmarket.NewInstanceTopUpTx(nil, &roflmarket.InstanceTopUp{
Provider: *providerAddr,
ID: machineID,
Term: term,
TermCount: topUpTermCount,
TermCount: roflCommon.TermCount,
})

acc := common.LoadAccount(cliConfig.Global(), npa.AccountName)
Expand Down Expand Up @@ -402,10 +401,6 @@ func showCommandArgs[V any](npa *common.NPASelection, raw []byte, args V) {
}

func init() {
topUpFlags := flag.NewFlagSet("", flag.ContinueOnError)
topUpFlags.StringVar(&topUpTerm, "term", roflCommon.TermMonth, "term to pay for in advance")
topUpFlags.Uint64Var(&topUpTermCount, "term-count", 1, "number of terms to pay for in advance")

showCmd.Flags().AddFlagSet(common.SelectorFlags)
showCmd.Flags().AddFlagSet(roflCommon.DeploymentFlags)

Expand All @@ -426,5 +421,5 @@ func init() {
topUpCmd.Flags().AddFlagSet(common.SelectorFlags)
topUpCmd.Flags().AddFlagSet(common.RuntimeTxFlags)
topUpCmd.Flags().AddFlagSet(roflCommon.DeploymentFlags)
topUpCmd.Flags().AddFlagSet(topUpFlags)
topUpCmd.Flags().AddFlagSet(roflCommon.TermFlags)
}
13 changes: 13 additions & 0 deletions docs/rofl.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ offer:

[ROFL marketplace]: https://github.com/oasisprotocol/oasis-sdk/blob/main/docs/rofl/features/marketplace.mdx

## Top-up payment for the machine {#top-up}

Run `rofl machine top-up` to extend the rental of the machine obtained from
the [ROFL marketplace]. The rental is extended under the terms of the original
offer. Specify the extension period with [`--term`][term-flags] and
[`--term-count`][term-flags] parameters.

![code shell](../examples/rofl/machine-top-up.in.static)

![code](../examples/rofl/machine-top-up.out.static)

[term-flags]: #deploy

## Advanced

### Upgrade ROFL app dependencies {#upgrade}
Expand Down
3 changes: 2 additions & 1 deletion examples/rofl/deploy.out.static
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ Transaction hash: bce96976f38485546b5950f8b2a7f9b7c43b9656935cc472a90680187469f4
Execution successful.
Created machine: 0000000000000000
Deployment into machine scheduled.
Use `oasis rofl machine show` to see status.
This machine expires on 2025-08-07 12:35:47 +0200 CEST. Use `oasis rofl machine top-up` to extend it.
Use `oasis rofl machine show` to check status.
1 change: 1 addition & 0 deletions examples/rofl/machine-top-up.in.static
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
oasis rofl machine top-up --term hour --term-count 12
34 changes: 34 additions & 0 deletions examples/rofl/machine-top-up.out.static
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Using provider: oasis1qp2ens0hsp7gh23wajxa4hpetkdek3swyyulyrmz (oasis1qp2ens0hsp7gh23wajxa4hpetkdek3swyyulyrmz)
Top-up machine: default [000000000000022a]
Top-up term: 12 x hour
Unlock your account.
? Passphrase:
You are about to sign the following transaction:
Format: plain
Method: roflmarket.InstanceTopUp
Body:
{
"provider": "oasis1qp2ens0hsp7gh23wajxa4hpetkdek3swyyulyrmz",
"id": "000000000000022a",
"term": 1,
"term_count": 12
}
Authorized signer(s):
1. AyZKkxNFeyqLI5HGTYqEmCcYxKGo/kueOzSHzdnrSePO (secp256k1eth)
Nonce: 996
Fee:
Amount: 0.0013614 TEST
Gas limit: 13614
(gas price: 0.0000001 TEST per gas unit)

Network: testnet
ParaTime: sapphire
Account: dave
? Sign this transaction? Yes
(In case you are using a hardware-based signer you may need to confirm on device.)
Broadcasting transaction...
Transaction included in block successfully.
Round: 12917124
Transaction hash: 094ddc21c39acd96789153003016bda5d2a0077e7be11635bb755b6c49c287ac
Execution successful.
Machine topped up.
Loading