native

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2024 License: BSD-3-Clause Imports: 3 Imported by: 7

Documentation

Overview

Package native implements an execution service to run native smart contracts.

A native smart contract is written in Go and packaged with the application.

Documentation Last Review: 08.10.2020

Index

Examples

Constants

View Source
const (
	// ContractArg is the argument key in the transaction to look up a contract.
	ContractArg = "go.dedis.ch/dela.ContractArg"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Contract

type Contract interface {
	Execute(store.Snapshot, execution.Step) error
	UID() string
}

Contract is the interface to implement to register a smart contract that will be executed natively.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is an execution service for packaged applications. Those applications have complete access to the trie and can directly update it.

- implements execution.Service

func NewExecution

func NewExecution() *Service

NewExecution returns a new native execution. The given service will be executed for every incoming transaction.

func (*Service) Execute

func (ns *Service) Execute(snap store.Snapshot, step execution.Step) (execution.Result, error)

Execute implements execution.Service. It uses the executor to process the incoming transaction and return the result.

Example
package main

import (
	"encoding/binary"
	"fmt"
	"sync"

	"go.dedis.ch/dela/core/execution"
	"go.dedis.ch/dela/core/store"
	"go.dedis.ch/dela/core/txn/signed"
	"go.dedis.ch/dela/crypto/bls"
)

func main() {
	srvc := NewExecution()
	srvc.Set("example", exampleContract{})

	store := newStore()
	signer := bls.NewSigner()

	increment := make([]byte, 8)
	binary.LittleEndian.PutUint64(increment, 5)

	opts := []signed.TransactionOption{
		signed.WithArg("increment", increment),
		signed.WithArg(ContractArg, []byte("example")),
	}

	tx, err := signed.NewTransaction(0, signer.GetPublicKey(), opts...)
	if err != nil {
		panic("failed to create transaction: " + err.Error())
	}

	step := execution.Step{
		Current: tx,
	}

	for i := 0; i < 2; i++ {
		res, err := srvc.Execute(store, step)
		if err != nil {
			panic("failed to execute: " + err.Error())
		}

		if res.Accepted {
			fmt.Println("accepted")
		}
	}

	value, err := store.Get([]byte("counter"))
	if err != nil {
		panic("store failed: " + err.Error())
	}

	fmt.Println(binary.LittleEndian.Uint64(value))

}

// exampleContract is an example contract that reads a counter value in the
// store and increase it with the increment in the transaction.
//
// - implements native.Contract
type exampleContract struct{}

// Execute implements native.Contract. It increases the counter with the
// increment in the transaction.
func (exampleContract) Execute(store store.Snapshot, step execution.Step) error {
	value, err := store.Get([]byte("counter"))
	if err != nil {
		return err
	}

	counter := uint64(0)
	if len(value) == 8 {
		counter = binary.LittleEndian.Uint64(value)
	}

	incr := binary.LittleEndian.Uint64(step.Current.GetArg("increment"))

	buffer := make([]byte, 8)
	binary.LittleEndian.PutUint64(buffer, counter+incr)

	err = store.Set([]byte("counter"), buffer)
	if err != nil {
		return err
	}

	return nil
}

func (exampleContract) UID() string {
	return "EXPL"
}

// inMemoryStore in a simple implementation of a store using an in-memory
// map.
//
// - implements store.Snapshot
type inMemoryStore struct {
	sync.Mutex

	entries map[string][]byte
}

func newStore() *inMemoryStore {
	return &inMemoryStore{
		entries: make(map[string][]byte),
	}
}

// Get implements store.Readable. It returns the value associated to the key.
func (s *inMemoryStore) Get(key []byte) ([]byte, error) {
	s.Lock()
	defer s.Unlock()

	return s.entries[string(key)], nil
}

// Set implements store.Writable. It sets the value for the key.
func (s *inMemoryStore) Set(key, value []byte) error {
	s.Lock()
	s.entries[string(key)] = value
	s.Unlock()

	return nil
}

// Delete implements store.Writable. It deletes the key from the store.
func (s *inMemoryStore) Delete(key []byte) error {
	s.Lock()
	delete(s.entries, string(key))
	s.Unlock()

	return nil
}
Output:

accepted
accepted
10

func (*Service) Set

func (ns *Service) Set(name string, contract Contract)

Set stores the contract using the name as the key. A transaction can trigger this contract by using the same name as the contract argument.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL