Difference between revisions of "Code"

From RunWiki
Jump to: navigation, search
Line 9: Line 9:
  
 
== Deploying ==
 
== Deploying ==
 +
 +
You deploy your classes and functions to Bitcoin. Deploying uploads your code in a Bitcoin transaction and creates a new output for it that you own. To deploy, you call run.deploy() and pass in your local class or function. Run will publish the transaction in the background and make you the owner of the new Code. Being the owner allows you to perform actions on it. Code is not necessarily static, as we'll see.
 +
 +
run.deploy() returns to you a new copy of your class or function that you should use going forward. This copy is special: unlike your original code, this copy is linked to your new Bitcoin output. It is also securely sandboxed and acquires several special Code methods that you can use to update it. We suggest adding the word Code to the name of the copy to differentiate it from your local class. You can call sync() on it right away to make sure that it deployed successfully.
 +
 +
We recommend you deploy all of your code in advance and load your load when your app starts. This way, your app and your users have a stable library to work with. You can do this by writing a script outside of your app.
 +
 +
Deploy a sidekick function
 +
 +
function sha256(data) { ... }
 +
 +
const sha256Code = run.deploy(sha256)
 +
 +
await sha256Code.sync()
 +
 
== Loading ==
 
== Loading ==
 +
You will want to load the code your deployed when your app starts. run.load(), in addition to loading jigs, is able to download, install and sandbox your classes and functions from the blockchain too. Just pass in the location of the code you wish to download.
 +
 +
Load a Data class
 +
 +
const Data = await run.load('<class-location-goes-here>')
 +
 +
const data = new Data('abc')
 +
 +
Alternatively, you can use the inventory to find your code. run.inventory.sync() will load all the code that you own and place it in the run.inventory.code array. You can filter that array by origin to find the code you plan to use.
 +
 +
Warning: Never search for code in your inventory by its name. Anyone can create and send you code with any name.
 +
 +
Find a class you own in the inventory
 +
 +
await run.inventory.sync()
 +
 +
const MyClass = run.inventory.code.find(C => C.origin === myClassOrigin)
 +
 
== Linking ==
 
== Linking ==
 +
 +
You can create code on Bitcoin that uses other code on Bitcoin, just like you would in your application. To do this, you have to explicitely tell Run that you are using other classes or functions, because Run needs to be able to link the code together.
 +
 +
You tell Run about other code you use by setting the deps property on your class or function. The deps property should be set to an object having all of the code you use inside. Those dependencies stored in deps will be made available as globals inside your class or function.
 +
 +
Deploy a jig class with a dependency
 +
 +
class Reward extends Jig { ... }
 +
 +
class LootBox extends Jig {
 +
  init() { this.reward = new Reward() }
 +
}
 +
 +
LootBox.deps = { Reward }
 +
 +
run.deploy(LootBox)
 +
 
== Extending ==
 
== Extending ==
 +
 +
You can create hierarchies of jig classes using Run. This is often useful for adding or changing some base class behavior. For example, think of a game where a base Vehicle class is extended to create many types of vehicles, like planes and trains.
 +
 +
To extend a class, you use the extends keyword as you normally would in JavaScript. When you deploy an extension class, Run will automatically create separate outputs for both the parent and the child and link them together. You do not need to add the parent class to the deps object on the child. Run is smart enough to automatically find the parent.
 +
 +
class EditablePost extends Post {
 +
  edit(message) {
 +
    this.message = message
 +
  }
 +
}
 +
 +
Inside methods on the child class, you can call the parent class's methods by using the super keyword in JavaScript. This is useful when you want to override a method on the parent to add behavior but you still want to call the parent method inside.
 +
 +
By default, extending a class requires the parent class's approval. This ensures the instanceof keyword is secure, because if Run didn't require parent class approval, third-parties could extend from a class to trick your instanceof checks into passing. Sometimes, however, you will want third-parties to extend your classes, and in those cases, set the sealed property on your class to false before you deploy so that anyone can create extensions.
 +
 +
 
== Syncing ==
 
== Syncing ==
 +
 +
When you call MyClass.sync(), it works just like myJig.sync(). If there are pending transactions, they will be published to the blockchain, and if there are network updates you haven't received, Run will download and apply them. We always recommend calling sync() after every code update to catch errors too, just like jigs. If you load a class by its origin, it is best to call sync() right after to make sure you have the latest state. For more about syncing, see Jigs: Syncing.
 +
 +
Load a class at its origin and fast-forward it to its latest state
 +
 +
const DigitalPet = await run.load('<digital-pet-class-origin>')
 +
 +
await DigitalPet.sync()
 +
 
== Updating ==
 
== Updating ==
 +
 +
You can call methods on jig classes just like jig objects. Class methods can change properties, call other class methods, and create instances. You can even send the code to someone else by changing its owner!
 +
 +
To write a jig class method, put static before the method name and it will apply to the class itself and not instances. When you call a class method, Run publishes a Bitcoin transaction with the update and assigns the code to a new location. Other jigs that use the code will see the updates when they sync.
 +
 +
You should think of code as living objects with their own history. Although only jig classes can have static methods that update their state, all code including sidekicks can be upgraded, destroyed, and authed.
 +
 +
class Weapon extends Jig {
 +
  static setPower(power) {
 +
    this.power = power
 +
  }
 +
}
 +
 +
const WeaponCode = run.deploy(Weapon)
 +
 +
WeaponCode.setPower(100)
 +
 +
// WeaponCode.power === 100
 +
 
== Upgrading ==
 
== Upgrading ==
 
== Trusting ==
 
== Trusting ==

Revision as of 03:57, 2 April 2023

With Run, you can own code, like classes and functions, just as easily as you can own objects. This may sound a little meta at first, but don't worry — you've been doing it all along! Every jig you created was linked to a jig class which you owned too. That jig class lived in its own output and had its own location.

When you own a piece of code, it means you have control over that behavior. For example, if you own a jig class, you get to decide what its jig instances are able to do. You can update or destroy that class and even call methods on it. Run calls classes and functions that people own Code with a capital C. Using Code, you can define new kinds of jigs, create reusable helper functions, share your server logic for auditability, discover algorithms from other apps, and much more.

There are two kinds of Code that Run supports:

  1. Jig classes: Jig classes are classes that extend from Jig and behave like jigs. You already know these. You can use them to create jig objects as we've already seen, but you can also call methods on them to update their properties over time. Jig classes evolve according to same Ownership Rules as jig objects.
  2. Sidekicks: Sidekicks are your helpers. They are your classes or functions that don't extend from Jig which you use more for supporting roles. You might use sidekicks to create a custom lock, to define a berry, to make a shared helper like expect, or even to store your server code on-chain. When you call a method on a sidekick, nothing gets recorded to Bitcoin. But you can call sidekicks from inside jigs and even from your own app. There are no restrictions on what kinds of parameters can be passed into or returned from sidekicks. Read more about Sidekicks here.

Using jig classes and sidekicks, you have a powerful repertoire to build extensible apps.

Deploying

You deploy your classes and functions to Bitcoin. Deploying uploads your code in a Bitcoin transaction and creates a new output for it that you own. To deploy, you call run.deploy() and pass in your local class or function. Run will publish the transaction in the background and make you the owner of the new Code. Being the owner allows you to perform actions on it. Code is not necessarily static, as we'll see.

run.deploy() returns to you a new copy of your class or function that you should use going forward. This copy is special: unlike your original code, this copy is linked to your new Bitcoin output. It is also securely sandboxed and acquires several special Code methods that you can use to update it. We suggest adding the word Code to the name of the copy to differentiate it from your local class. You can call sync() on it right away to make sure that it deployed successfully.

We recommend you deploy all of your code in advance and load your load when your app starts. This way, your app and your users have a stable library to work with. You can do this by writing a script outside of your app.

Deploy a sidekick function

function sha256(data) { ... }

const sha256Code = run.deploy(sha256)

await sha256Code.sync()

Loading

You will want to load the code your deployed when your app starts. run.load(), in addition to loading jigs, is able to download, install and sandbox your classes and functions from the blockchain too. Just pass in the location of the code you wish to download.

Load a Data class

const Data = await run.load('<class-location-goes-here>')

const data = new Data('abc')

Alternatively, you can use the inventory to find your code. run.inventory.sync() will load all the code that you own and place it in the run.inventory.code array. You can filter that array by origin to find the code you plan to use.

Warning: Never search for code in your inventory by its name. Anyone can create and send you code with any name.

Find a class you own in the inventory

await run.inventory.sync()

const MyClass = run.inventory.code.find(C => C.origin === myClassOrigin)

Linking

You can create code on Bitcoin that uses other code on Bitcoin, just like you would in your application. To do this, you have to explicitely tell Run that you are using other classes or functions, because Run needs to be able to link the code together.

You tell Run about other code you use by setting the deps property on your class or function. The deps property should be set to an object having all of the code you use inside. Those dependencies stored in deps will be made available as globals inside your class or function.

Deploy a jig class with a dependency

class Reward extends Jig { ... }

class LootBox extends Jig {

 init() { this.reward = new Reward() }

}

LootBox.deps = { Reward }

run.deploy(LootBox)

Extending

You can create hierarchies of jig classes using Run. This is often useful for adding or changing some base class behavior. For example, think of a game where a base Vehicle class is extended to create many types of vehicles, like planes and trains.

To extend a class, you use the extends keyword as you normally would in JavaScript. When you deploy an extension class, Run will automatically create separate outputs for both the parent and the child and link them together. You do not need to add the parent class to the deps object on the child. Run is smart enough to automatically find the parent.

class EditablePost extends Post {

 edit(message) {
   this.message = message
 }

}

Inside methods on the child class, you can call the parent class's methods by using the super keyword in JavaScript. This is useful when you want to override a method on the parent to add behavior but you still want to call the parent method inside.

By default, extending a class requires the parent class's approval. This ensures the instanceof keyword is secure, because if Run didn't require parent class approval, third-parties could extend from a class to trick your instanceof checks into passing. Sometimes, however, you will want third-parties to extend your classes, and in those cases, set the sealed property on your class to false before you deploy so that anyone can create extensions.


Syncing

When you call MyClass.sync(), it works just like myJig.sync(). If there are pending transactions, they will be published to the blockchain, and if there are network updates you haven't received, Run will download and apply them. We always recommend calling sync() after every code update to catch errors too, just like jigs. If you load a class by its origin, it is best to call sync() right after to make sure you have the latest state. For more about syncing, see Jigs: Syncing.

Load a class at its origin and fast-forward it to its latest state

const DigitalPet = await run.load('<digital-pet-class-origin>')

await DigitalPet.sync()

Updating

You can call methods on jig classes just like jig objects. Class methods can change properties, call other class methods, and create instances. You can even send the code to someone else by changing its owner!

To write a jig class method, put static before the method name and it will apply to the class itself and not instances. When you call a class method, Run publishes a Bitcoin transaction with the update and assigns the code to a new location. Other jigs that use the code will see the updates when they sync.

You should think of code as living objects with their own history. Although only jig classes can have static methods that update their state, all code including sidekicks can be upgraded, destroyed, and authed.

class Weapon extends Jig {

 static setPower(power) {
   this.power = power
 }

}

const WeaponCode = run.deploy(Weapon)

WeaponCode.setPower(100)

// WeaponCode.power === 100

Upgrading

Trusting