Class Context

java.lang.Object
convex.core.lang.Context

public class Context extends Object
Representation of CVM execution context.

Execution context includes: - The current on-Chain state, including the defined execution environment for each Address - Local lexical bindings for the current execution position - The identity (as an Address) for the origin, caller and currently executing actor - Juice and execution depth current status for - Result of the last operation executed (which may be exceptional)

Interestingly, this behaves like Scala's ZIO[Context-Stuff, AExceptional, T]

Contexts maintain checks on execution depth and juice to control against arbitrary on-chain execution. Coupled with limits on total juice and limits on memory allocation per unit juice, this places an upper bound on execution time and space.

Contexts also support returning exceptional values. Exceptional results may come from arbitrary nested depth (which requires a bit of complexity to reset depth when catching exceptional values). We avoid using Java exceptions here, because exceptionals are "normal" in the context of on-chain execution, and we'd like to avoid the overhead of exception handling - may be especially important in DoS scenarios.

"If you have a procedure with 10 parameters, you probably missed some" - Alan Perlis

  • Field Details

    • EMPTY_BINDINGS

      public static final AVector<ACell> EMPTY_BINDINGS
  • Constructor Details

  • Method Details

    • createFake

      public static Context createFake(State state)
      Creates an execution context with a default actor address. Useful for Testing
      Parameters:
      state - State to use for this Context
      Returns:
      Fake context
    • createFake

      public static Context createFake(State state, Address origin)
      Creates a "fake" execution context for the given address. Not valid for use in real transactions, but can be used to compute stuff off-chain "as-if" the actor made the call.
      Parameters:
      state - State to use for this Context
      origin - Origin address to use
      Returns:
      Fake context
    • createInitial

      public static Context createInitial(State state, Address origin, long juiceLimit)
      Creates an initial execution context with the specified actor as origin, and reserving the appropriate amount of juice. Juice reserve is extracted from the actor's current balance.
      Parameters:
      state - Initial State for Context
      origin - Origin Address for Context
      juiceLimit - Initial juice requested for Context
      Returns:
      Initial execution context with reserved juice.
    • completeTransaction

      public Context completeTransaction(State initialState, long juicePrice)
      Performs key actions at the end of a transaction:
      • Refunds juice
      • Accumulates used juice fees in globals
      • Increments sequence number
      Parameters:
      initialState - State before transaction execution (after prepare)
      juicePrice - Juice price of current execution
      Returns:
      Updated context
    • withState

      public Context withState(State newState)
    • getState

      public State getState()
      Get the latest state from this Context
      Returns:
      State instance
    • getJuiceUsed

      public long getJuiceUsed()
      Get the juice used so far in this Context
      Returns:
      Juice used
    • getJuiceAvailable

      public long getJuiceAvailable()
      Get the juice available in this Context
      Returns:
      Juice available
    • getJuiceLimit

      public long getJuiceLimit()
      Get the juice limit in this Context
      Returns:
      Juice limit
    • getOffer

      public long getOffer()
      Get the current offer from this Context
      Returns:
      Offered amount in Convex copper
    • getEnvironment

      public AHashMap<Symbol,ACell> getEnvironment()
      Gets the current Environment
      Returns:
      Environment map
    • getCompilerState

      public Context.CompilerState getCompilerState()
      Gets the compiler state
      Returns:
      CompilerState instance
    • getMetadata

      public AHashMap<Symbol,AHashMap<ACell,ACell>> getMetadata()
      Gets the metadata for the current Account
      Returns:
      Metadata map
    • consumeJuice

      public Context consumeJuice(long gulp)
      Consumes juice, returning an updated context if sufficient juice remains or an exceptional JUICE error.
      Parameters:
      gulp - Amount of juice to consume
      Returns:
      Updated context with juice consumed
    • checkJuice

      public boolean checkJuice(long gulp)
      Checks if there is sufficient juice for a given gulp of consumption. Does not alter context in any way.
      Parameters:
      gulp - Amount of juice to be consumed.
      Returns:
      true if juice is sufficient, false otherwise.
    • lookup

      public Context lookup(Symbol symbol)
      Looks up a symbol's value in the current execution context, without any effect on the Context (no juice consumed etc.)
      Parameters:
      symbol - Symbol to look up. May be qualified
      Returns:
      Context with the result of the lookup (may be an undeclared exception)
    • lookupDynamic

      public Context lookupDynamic(Symbol symbol)
      Looks up a value in the dynamic environment. Consumes no juice. Returns an UNDECLARED exception if the symbol cannot be resolved.
      Parameters:
      symbol - Symbol to look up
      Returns:
      Updated Context
    • lookupDynamic

      public Context lookupDynamic(Address address, Symbol symbol)
      Looks up a value in the dynamic environment. Consumes no juice. Returns an UNDECLARED exception if the symbol cannot be resolved. Returns a NOBODY exception if the specified Account does not exist
      Parameters:
      address - Address of account in which to look up value
      symbol - Symbol to look up
      Returns:
      Updated Context
    • lookupMeta

      public AHashMap<ACell,ACell> lookupMeta(Symbol sym)
      Looks up Metadata for the given symbol in this context
      Parameters:
      sym - Symbol to look up
      Returns:
      Metadata for given symbol (may be empty) or null if undeclared
    • lookupMeta

      public AHashMap<ACell,ACell> lookupMeta(Address address, Symbol sym)
      Looks up Metadata for the given symbol in this context
      Parameters:
      address - Address to use for lookup (may pass null for current environment)
      sym - Symbol to look up
      Returns:
      Metadata for given symbol (may be empty) or null if undeclared
    • lookupDefiningAccount

      public AccountStatus lookupDefiningAccount(Address address, Symbol sym)
      Looks up the account the defines a given Symbol
      Parameters:
      sym - Symbol to look up
      address - Address to look up in first instance (null for current address).
      Returns:
      AccountStatus for given symbol (may be empty) or null if undeclared
    • lookupValue

      public ACell lookupValue(Symbol sym)
      Looks up value for the given symbol in this context
      Parameters:
      sym - Symbol to look up
      Returns:
      Value for the given symbol or null if undeclared
    • lookupValue

      public ACell lookupValue(Address address, Symbol sym)
      Looks up value for the given symbol in this context
      Parameters:
      address - Address to look up in (may be null for current environment)
      sym - Symbol to look up
      Returns:
      Value for the given symbol or null if undeclared
    • lookupDynamicEntry

      public MapEntry<Symbol,ACell> lookupDynamicEntry(Address address, Symbol sym)
      Looks up an environment entry for a specific address without consuming juice.
      Parameters:
      address - Address of Account in which to look up entry
      sym - Symbol to look up
      Returns:
      Environment entry
    • getAccountStatus

      public AccountStatus getAccountStatus()
      Gets the account status for the current Address
      Returns:
      AccountStatus object, or null if not found
    • getHoldings

      public BlobMap<Address,ACell> getHoldings()
      Gets the holdings map for the current account.
      Returns:
      Map of holdings, or null if the current account does not exist.
    • getBalance

      public long getBalance()
      Gets the balance for the current Address
      Returns:
      Balance in Convex Coins
    • getBalance

      public long getBalance(Address address)
      Gets the balance for the specified Address
      Parameters:
      address - Address to check balance for
      Returns:
      Balance in Convex Coins
    • getCaller

      public Address getCaller()
      Gets the caller of the currently executing context. Will be null if this context was not called from elsewhere (e.g. is an origin context)
      Returns:
      Caller of the currently executing context
    • getScope

      public ACell getScope()
      Gets the scope of the currently executing context. Will be null if no scope was set
      Returns:
      Caller of the currently executing context
    • getAddress

      public Address getAddress()
      Gets the address of the currently executing Account. May be the current actor, or the address of the account that executed this transaction if no Actors have been called.
      Returns:
      Address of the current account, cannot be null, must be a valid existing account
    • getResult

      public <R extends ACell> R getResult()
      Gets the result from this context. Throws an Error if the context return value is exceptional.
      Returns:
      Result value from this Context.
    • getValue

      public Object getValue()
      Gets the resulting value from this context. May be either exceptional or a normal result.
      Returns:
      Either the normal result, or an AExceptional instance
    • getExceptional

      public AExceptional getExceptional()
      Gets the exceptional value from this context. Throws an Error is the context return value is normal.
      Returns:
      an AExceptional instance
    • withResult

      public Context withResult(ACell value)
      Returns a context updated with the specified result. Context may become exceptional depending on the result type.
      Parameters:
      value - Value
      Returns:
      Context updated with the specified result.
    • withValue

      public Context withValue(Object value)
      Updates this context with a given value, which may either be a normal result or exceptional value
      Parameters:
      value - Value
      Returns:
      Context updated with the specified result value.
    • withResult

      public Context withResult(long gulp, ACell value)
    • withJuiceError

      public Context withJuiceError()
      Returns this context with a JUICE error, consuming all juice.
      Returns:
      Exceptional Context signalling JUICE error.
    • withException

      public Context withException(AExceptional exception)
    • withException

      public Context withException(long gulp, AExceptional value)
    • execute

      public Context execute(AOp<?> op)
      Executes an Op within this context, returning an updated context.
      Parameters:
      op - Op to execute
      Returns:
      Updated Context
    • run

      public Context run(AOp<?> op)
      Executes an Op at the top level in a new forked Context. Handles top level halt, recur and return. Returning an updated context containing the result or an exceptional error.
      Parameters:
      op - Op to execute
      Returns:
      Updated Context
    • run

      public Context run(ACell code)
      Executes a form at the top level in a new forked Context. Handles top level halt, recur and return. Returning an updated context containing the result or an exceptional error.
      Parameters:
      code - Code to execute
      Returns:
      Updated Context
    • invoke

      public Context invoke(AFn<?> fn, ACell... args)
      Invokes a function within this context, returning an updated context. Handles function recur and return values. Keeps depth constant upon return.
      Parameters:
      fn - Function to execute
      args - Arguments for function
      Returns:
      Updated Context
    • executeLocalBinding

      public Context executeLocalBinding(ACell bindingForm, AOp<?> op)
      Execute an op, and bind the result to the given binding form in the lexical environment Binding form may be a destructuring form
      Parameters:
      bindingForm - Binding form
      op - Op to execute to get binding values
      Returns:
      Context with local bindings updated
    • updateBindings

      public Context updateBindings(ACell bindingForm, Object args)
      Updates local bindings with a given binding form
      Parameters:
      bindingForm - Binding form
      args - Arguments to bind
      Returns:
      Non-exceptional Context with local bindings updated, or an exceptional result if bindings fail
    • print

      public boolean print(BlobBuilder bb, long limit)
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • getLocalBindings

      public AVector<ACell> getLocalBindings()
    • withLocalBindings

      public Context withLocalBindings(AVector<ACell> newBindings)
      Updates this Context with new local bindings. Doesn't affact result state (exceptional or otherwise)
      Parameters:
      newBindings - New local bindings map to use.
      Returns:
      Updated context
    • getAccountStatus

      public AccountStatus getAccountStatus(Address address)
      Gets the account status record, or null if not found
      Parameters:
      address - Address of account
      Returns:
      AccountStatus for the specified address, or null if the account does not exist
    • getDepth

      public int getDepth()
    • getOrigin

      public Address getOrigin()
    • define

      public Context define(Symbol key, ACell value)
      Defines a value in the environment of the current address
      Parameters:
      key - Symbol of the mapping to create
      value - Value to define
      Returns:
      Updated context with symbol defined in environment
    • defineWithSyntax

      public Context defineWithSyntax(Syntax syn, ACell value)
      Defines a value in the environment of the current address, updating the metadata
      Parameters:
      syn - Syntax Object to define, containing a Symbol value
      value - Value to set of the given Symbol
      Returns:
      Updated context with symbol defined in environment
    • undefine

      public Context undefine(Symbol key)
      Removes a definition mapping in the environment of the current address
      Parameters:
      key - Symbol of the environment mapping to remove
      Returns:
      Updated context with symbol definition removed from the environment, or this context if unchanged
    • expandCompile

      public Context expandCompile(ACell form)
      Expand and compile a form in this Context.
      Parameters:
      form - Form to expand and compile
      Returns:
      Updated Context with compiled Op as result
    • compile

      public Context compile(ACell expandedForm)
      Compile a form in this Context. Form must already be fully expanded to a Syntax Object
      Parameters:
      expandedForm - Form to compile
      Returns:
      Updated Context with compiled Op as result
    • eval

      public Context eval(ACell form)
      Executes a form in the current context. Ops are executed directly. Other forms will be expanded and compiled before execution, unless *lang* is set, in which case they will be executed via the *lang* function.
      Parameters:
      form - Form to evaluate
      Returns:
      Context containing the result of evaluating the specified form
    • evalAs

      public Context evalAs(Address address, ACell form)
      Evaluates a form as another Address. Causes TRUST error if the Address is not controlled by the current address.
      Parameters:
      address - Address of Account in which to evaluate
      form - Form to evaluate
      Returns:
      Updated Context
    • query

      public Context query(ACell form)
      Executes code as if run in the current account, but always discarding state changes.
      Parameters:
      form - Code to execute.
      Returns:
      Context updated with only query result and juice consumed
    • queryAs

      public Context queryAs(Address address, ACell form)
      Executes code as if run in the specified account, but always discarding state changes.
      Parameters:
      address - Address of Account in which to execute the query
      form - Code to execute.
      Returns:
      Context updated with only query result and juice consumed
    • handleQueryResult

      protected Context handleQueryResult(Context ctx)
      Just take result and juice from query. Log and state not kept.
      Parameters:
      ctx -
      Returns:
    • compileAll

      public Context compileAll(ASequence<ACell> forms)
      Compiles a sequence of forms in the current context. Returns a vector of ops in the updated Context. Maintains depth.
      Parameters:
      forms - A sequence of forms to compile
      Returns:
      Updated context with vector of compiled forms
    • withJuice

      public Context withJuice(long newJuice)
    • withJuiceLimit

      public Context withJuiceLimit(long newJuiceLimit)
    • withCompilerState

      public Context withCompilerState(Context.CompilerState comp)
    • isExceptional

      public boolean isExceptional()
      Tests if this Context holds an exceptional result. Ops should cancel and return exceptional results unchanged, unless they can handle them.
      Returns:
      true if context has an exceptional value, false otherwise
    • isValidAccount

      public boolean isValidAccount(Address address)
      Tests if an Address is valid, i.e. refers to an existing Account
      Parameters:
      address - Address to check. May be null
      Returns:
      true if Account exists, false otherwise
    • isError

      public boolean isError()
      Tests if this Context's current status contains an Error. Errors are an uncatchable subset of Exceptions.
      Returns:
      true if context has an Error value, false otherwise
    • transfer

      public Context transfer(Address target, long amount)
      Transfers funds from the current address to the target. Uses no juice
      Parameters:
      target - Target Address, will be created if does not already exist.
      amount - Amount to transfer, must be between 0 and Amount.MAX_VALUE inclusive
      Returns:
      Context with sent amount if the transaction succeeds, or an exceptional value if the transfer fails
    • transferMemoryAllowance

      public Context transferMemoryAllowance(Address target, CVMLong amountToSend)
      Transfers memory allowance from the current address to the target. Uses no juice
      Parameters:
      target - Target Address, must already exist
      amountToSend - Amount of memory to transfer, must be between 0 and Amount.MAX_VALUE inclusive
      Returns:
      Context with a null result if the transaction succeeds, or an exceptional value if the transfer fails
    • setMemory

      public Context setMemory(long allowance)
      Sets the memory allowance for the current account, buying / selling from the pool as necessary to ensure the correct final allowance
      Parameters:
      allowance - New memory allowance
      Returns:
      Context indicating the price paid for the allowance change (may be zero or negative for refund)
    • acceptFunds

      public Context acceptFunds(long amount)
      Accepts offered funds for the given address. STATE error if offered amount is insufficient. ARGUMENT error if acceptance is negative.
      Parameters:
      amount - Amount to accept
      Returns:
      Updated context, with long amount accepted as result
    • actorCall

      public Context actorCall(ACell target, long offer, String functionName, ACell... args)
      Executes a call to an Actor. Utility function which convert a java String function name
      Parameters:
      target - Target Actor address or scope vector
      offer - Amount of Convex Coins to offer in Actor call
      functionName - Symbol of function name defined by Actor
      args - Arguments to Actor function invocation
      Returns:
      Context with result of Actor call (may be exceptional)
    • actorCall

      public Context actorCall(ACell target, long offer, ACell functionName, ACell... args)
      Executes a call to an Actor.
      Parameters:
      target - Target Actor address
      offer - Amount of Convex Coins to offer in Actor call
      functionName - Symbol of function name defined by Actor
      args - Arguments to Actor function invocation
      Returns:
      Context with result of Actor call (may be exceptional)
    • handleStateResults

      public Context handleStateResults(Context returnContext, boolean rollback)
      Handle results at the end of an execution boundary (actor call, transaction etc.)
      Parameters:
      returnContext - Context containing return from child transaction / call
      rollback - If true, always rolls back state effects
      Returns:
      Updated parent context
    • deployActor

      public Context deployActor(ACell... code)
      Deploys an Actor in this context. Argument argument must be an Actor generation code, which will be evaluated in the new Actor account to initialise the Actor. Result will contain the new Actor address if successful, an exception otherwise.
      Parameters:
      code - Actor initialisation code
      Returns:
      Updated Context with Actor deployed, or an exceptional result
    • createAccount

      public Context createAccount(AccountKey key)
      Create a new Account with a given AccountKey (may be null for actors etc.)
      Parameters:
      key - New Account Key
      Returns:
      Updated context with new Account added
    • withError

      public Context withError(Keyword error)
    • withError

      public Context withError(Keyword errorCode, String message)
    • withError

      public Context withError(Keyword errorCode, ACell rs)
    • withError

      public Context withError(ErrorValue error)
    • withArityError

      public Context withArityError(String message)
    • withCompileError

      public Context withCompileError(String message)
    • withBoundsError

      public Context withBoundsError(long index)
    • withCastError

      public Context withCastError(int argIndex, AType klass)
    • withCastError

      public Context withCastError(int argIndex, ACell[] args, AType klass)
    • withCastError

      public Context withCastError(ACell a, AType klass)
    • withCastError

      public Context withCastError(AType klass)
    • withCastError

      public Context withCastError(ACell a, String message)
    • getErrorCode

      public ACell getErrorCode()
      Gets the error code of this context's return value
      Returns:
      The ErrorType of the current exceptional value, or null if there is no error.
    • getError

      public ErrorValue getError()
      Gets the Error from this Context, or null if not an Error
      Returns:
      The ErrorType of the current exceptional value, or null if there is no error.
    • withAssertError

      public Context withAssertError(String message)
    • withFundsError

      public Context withFundsError(String message)
    • withArgumentError

      public Context withArgumentError(String message)
    • getTimeStamp

      public CVMLong getTimeStamp()
      Gets the current timestamp for this context. The timestamp is the greatest timestamp of all blocks in consensus (including the currently executing block).
      Returns:
      Timestamp in milliseconds since UNIX epoch
    • schedule

      public Context schedule(long time, AOp<?> op)
      Schedules an operation for the specified future timestamp. Handles integrity checks and schedule juice.
      Parameters:
      time - Timestamp at which to schedule the op.
      op - Operation to schedule.
      Returns:
      Updated context, with scheduled time as the result
    • setDelegatedStake

      public Context setDelegatedStake(AccountKey peerKey, long newStake)
      Sets the delegated stake on a specified peer to the specified level. May set to zero to remove stake. Stake will be capped by current balance.
      Parameters:
      peerKey - Peer Account key on which to stake
      newStake - Amount to stake
      Returns:
      Context with amount of coins transferred to Peer as result (may be negative if stake withdrawn)
    • setPeerStake

      public Context setPeerStake(AccountKey peerKey, long newStake)
      Sets the stake for a given Peer, transferring coins from the current address.
      Parameters:
      peerKey - Peer Account Key for which to update Stake
      newStake - New stake for Peer
      Returns:
      Updated Context
    • createPeer

      public Context createPeer(AccountKey accountKey, long initialStake)
      Creates a new peer with the specified stake. The accountKey must not be in the list of peers. The accountKey must be assigend to the current transaction address Stake must be greater than 0. Stake must be less than to the account balance.
      Parameters:
      accountKey - Peer Account key to create the PeerStatus
      initialStake - Initial stake amount
      Returns:
      Context with final take set
    • setPeerData

      public Context setPeerData(AccountKey peerKey, AHashMap<ACell,ACell> data)
      Sets peer data.
      Parameters:
      peerKey - Peer to set data for
      data - Map of data to set for the peer
      Returns:
      Context with final peer data set
    • setHolding

      public Context setHolding(Address targetAddress, ACell value)
      Sets the holding for a specified target account. Returns NOBODY exception if account does not exist.
      Parameters:
      targetAddress - Account address at which to set the holding
      value - Value to set for the holding.
      Returns:
      Updated context
    • setController

      public Context setController(ACell address)
      Sets the controller for the current Account
      Parameters:
      address - New controller Address
      Returns:
      Context with current Account controller set
    • setAccountKey

      public Context setAccountKey(AccountKey publicKey)
      Sets the public key for the current account
      Parameters:
      publicKey - New Account Public Key
      Returns:
      Context with current Account Key set
    • withAccountStatus

      protected Context withAccountStatus(Address target, AccountStatus accountStatus)
    • forkWithAddress

      public Context forkWithAddress(Address newAddress)
      Switches the context to a new address, creating a new execution context. Suitable for testing.
      Parameters:
      newAddress - New Address to use.
      Returns:
      Result type of new Context
    • fork

      public Context fork()
      Forks this context, creating a new copy of all local state
      Returns:
      A new forked Context
    • appendLog

      public Context appendLog(AVector<ACell> values)
      Appends a log entry for the current address.
      Parameters:
      values - Values to log
      Returns:
      Updated Context
    • getLog

      public AVector<AVector<ACell>> getLog()
      Gets the log map for the current context.
      Returns:
      BlobMap of addresses to log entries created in the course of current execution context.
    • lookupCNS

      public Context lookupCNS(String name)
    • expand

      public Context expand(ACell form)
      Expands a form with the default *initial-expander*
      Parameters:
      form - Form to expand
      Returns:
      Syntax Object resulting from expansion.
    • expand

      public Context expand(AFn<?> expander, ACell form, AFn<?> cont)
    • lookupExpander

      public AFn<ACell> lookupExpander(ACell form)
      Looks up an expander from a form in this context
      Parameters:
      form - Form which might be an expander reference (either a symbol or (lookup...) form)
      Returns:
      Expander instance, or null if no expander found