GithubHelp home page GithubHelp logo

onflow / cadence Goto Github PK

View Code? Open in Web Editor NEW
526.0 44.0 140.0 80.87 MB

Cadence, the resource-oriented smart contract programming language ๐Ÿƒโ€โ™‚๏ธ

Home Page: https://developers.flow.com/cadence

License: Apache License 2.0

Makefile 0.03% Go 98.66% Haskell 0.01% Shell 0.03% TypeScript 0.48% JavaScript 0.13% Python 0.20% HTML 0.02% Cadence 0.44% CSS 0.02%
cadence language programming-language smart-contracts onflow hacktoberfest

cadence's People

Contributors

benjaminkvm avatar bjartek avatar bluesign avatar darkdrag00nv2 avatar dependabot[bot] avatar dreamsmasher avatar dsainati1 avatar dwightguth avatar franklywatson avatar fxamacker avatar ianthpun avatar j1010001 avatar janezpodhostnik avatar jordanschalm avatar joshuahannan avatar jribbink avatar m-peter avatar m4ksio avatar maxstalker avatar objectplayer avatar psiemens avatar ramtinms avatar robert-e-davidson3 avatar rrrkren avatar sideninja avatar snyk-bot avatar supuns avatar tarakby avatar turbolent avatar zhangchiqing avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cadence's Issues

Update subtyping rules for non-composite references

Problem

Initially we only allowed references to resources, but extended this also to non-resource types. However, the subtyping rules for references only consider composite types. The subtyping rules for non-composite references need to be updated to not only consider composite types, e.g. &Int <: &AnyStruct.

Steps to Reproduce

let x = 1
let xRef = &x as &Int
let anyRef: &AnyStruct = xRef

Acceptance Criteria

  • Subtyping for non-composite types should work correctly

Move storage encoding/decoding

Context

The current storage interface is low-level: It is key-value based, where keys and values are byte arrays, and the encoding/decoding of Cadence values is implemented in the interpreter. In addition, the interpreter optimizes how an object graph is stored, by decomposing it into multiple key-value pairs.

Proposal

  • Make the storage read/write operations higher-level: Instead of low-level byte arrays for keys and values, provide and request high-level value types
  • Move the encoding/decoding out of Cadence, or at least out of the interpreter package. Like fvm, it could live in flow-go, or a separate package in this repository

Problems / Open Questions

  • The current storage optimization to write parts of the object graph to separate storage keys and defer loading them until they are accessed requires knowledge about the kinds of operations that are performed. Currently this optimization is performed for dictionaries, and operations such as getting an value for a key, removing a key, and destroying the dictionary need to perform storage operations.

    • func (v *DictionaryValue) Get(inter *Interpreter, _ LocationRange, keyValue Value) Value {
      key := dictionaryKey(keyValue)
      value, ok := v.Entries[key]
      if ok {
      return NewSomeValueOwningNonCopying(value)
      }
      // Is the key a deferred value? If so, load it from storage
      // and keep it as an entry in memory
      if v.DeferredKeys != nil {
      storageKey, ok := v.DeferredKeys[key]
      if ok {
      delete(v.DeferredKeys, key)
      if v.prevDeferredKeys == nil {
      v.prevDeferredKeys = map[string]string{}
      }
      v.prevDeferredKeys[key] = storageKey
      storedValue := inter.readStored(*v.DeferredOwner, storageKey, true)
      v.Entries[key] = storedValue.(*SomeValue).Value
      // NOTE: *not* writing nil to the storage key,
      // as this would result in a loss of the value:
      // the read value is not modified,
      // so it won't be written back
      return storedValue
      }
      }
      return NilValue{}
      }
    • func (v *DictionaryValue) Destroy(interpreter *Interpreter, locationRange LocationRange) trampoline.Trampoline {
      var result trampoline.Trampoline = trampoline.Done{}
      maybeDestroy := func(value interface{}) {
      destroyableValue, ok := value.(DestroyableValue)
      if !ok {
      return
      }
      result = result.
      FlatMap(func(_ interface{}) trampoline.Trampoline {
      return destroyableValue.Destroy(interpreter, locationRange)
      })
      }
      for _, keyValue := range v.Keys.Values {
      // Don't use `Entries` here: the value might be deferred and needs to be loaded
      value := v.Get(interpreter, locationRange, keyValue)
      maybeDestroy(keyValue)
      maybeDestroy(value)
      }
      for _, storageKey := range v.DeferredKeys {
      interpreter.writeStored(*v.DeferredOwner, storageKey, NilValue{})
      }
      for _, storageKey := range v.prevDeferredKeys {
      interpreter.writeStored(*v.DeferredOwner, storageKey, NilValue{})
      }
      return result
      }
    • func (v *DictionaryValue) Remove(inter *Interpreter, locationRange LocationRange, keyValue Value) OptionalValue {
      v.modified = true
      // Don't use `Entries` here: the value might be deferred and needs to be loaded
      value := v.Get(inter, locationRange, keyValue)
      key := dictionaryKey(keyValue)
      // If a resource that was previously deferred is removed from the dictionary,
      // we delete its old key in storage, and then rely on resource semantics
      // to make sure it is stored or destroyed later
      if v.prevDeferredKeys != nil {
      if storageKey, ok := v.prevDeferredKeys[key]; ok {
      inter.writeStored(*v.DeferredOwner, storageKey, NilValue{})
      }
      }
      switch value := value.(type) {
      case *SomeValue:
      delete(v.Entries, key)
      // TODO: optimize linear scan
      for i, keyValue := range v.Keys.Values {
      if dictionaryKey(keyValue) == key {
      v.Keys.Remove(i)
      return value
      }
      }
      // Should never occur, the key should have been found
      panic(errors.NewUnreachableError())
      case NilValue:
      return value
      default:
      panic(errors.NewUnreachableError())
      }
      }
  • What type should the storage interface use? Currently the written/read values are of type interpreter.Value and serialized using a special CBOR encoder and decoder. This could be considered an implementation detail, and the value type intended for external use, cadence.Value, would be more appropriate. However, this type does not support the deferral optimization. Should it be implemented for cadence.Value instead? Also, we would need to port the CBOR encoding/decoding to cadence.Value.

    A solution could be to move the value hierarchy interpreter.Value out of the interpreter package into a separate package, or even "merge" it with cadence.Value. This would also reduce the amount of code and maintenance required to support multiple value hierarchies, plus the associated conversion cost.

cc @ramtinms @m4ksio @psiemens

BUG: Objects shouldn't be able to use themselves as arguments to their functions

Problem

If a resource or struct has a member function that takes a resource of the same type as an argument, then it should not be able to use itself as an argument.

Steps to Reproduce

  1. Copy this contract:
pub contract Nodes {

    pub resource Test {
        pub fun deposit(from: @Test) {
            destroy from
        }
    }

    init() {

        let test <- create Test()

        // this line should fail
        test.deposit(from: <-test)
    }
}
  1. See that there is no error reported

Acceptance Criteria

Should invalidate the object that is being invoked so it cannot be used as an argument to itself.

Division and Modulo for UFix64 and Fix64 is not implemented yet

Instructions

Please fill out the template below to the best of your ability.

Issue To Be Solved

Division for UFix64 and Fix64 is not implemented yet.
The error message was not clear to what's wrong within the contract.

Code example:

let result = Fix64(10) / Fix64(2)

Playground Error:

Error: GraphQL error: failed to deploy account code: Execution failed: TODO

(Optional): Suggest A Solution

Maybe including more info about the function that breaks would help with debugging.

Execution failed: TODO [U]Fix64 division.

(Optional): Context

(Replace this text:
What are you currently working on that this is blocking?)

Prevent certain types of values to be stored in fields

Context

Like we now forbid functions to be stored in fields through #62, also prevent certain other types to be stored in fields:

  • References
  • Accounts (Auth/Public)
  • Contracts
  • Blocks

Unlike in #62 for functions, we don't want to remove the subtyping rule.

Definition of Done

  • Interpreter: Remove types from member assignment allow list
  • Checker: Remove types from member assignment allow list

Add a Crypto contract

Context

Contracts may want to verify signatures.

Implement a new Crypto module which defines:

  • A type for signature algorithms, SignatureAlgorithm, and constants for the following signature algorithms:
    • Elliptic Curve Digital Signature Algorithm (ECDSA) on the NIST P-256 curve
    • Elliptic Curve Digital Signature Algorithm (ECDSA) on the secp256k1 curve
  • A type for hash algorithms, HashAlgorithm, and constants for the following hash algorithms:
    • Secure Hashing Algorithm 2 (SHA-2) with a 256-bit digest
    • Secure Hashing Algorithm 3 (SHA-3) with a 256-bit digest
  • A type for public keys, PublicKey, wich consists of the key data and signature algorithm
  • A type for a collection of public keys, KeyList, which allows:
    • Adding entries (fun add(_ publicKey: PublicKey, hashAlgorithm: HashAlgorithm, weight: UInt32): KeyListEntry)
    • Getting entries (fun get(keyIndex: Int): KeyListEntry?)
    • Revoking entries (fun revoke(keyIndex: Int); entries cannot be deleted)
    • Checking the validity of a set of signatures for some given data
      (fun isValid(signatureSet: [KeyListSignature], signedData: [UInt8]): Bool).
      As key list entries have a weight, this function supports the multi-sig use-case.
  • A type for a key list entry, KeyListEntry, which has an index (keyIndex), public key (publicKey), hash algorithm (hashAlgorithm), and has a weight
  • A type for signatures, KeyListSignature, which consists of the signature data (signature), and refers to a key in a key list through a key index (keyIndex)

Proposal

pub struct interface SignatureVerifier  {

    pub fun verify(
        signature: [UInt8],
        tag: String,
        signedData: [UInt8],
        publicKey: [UInt8],
        signatureAlgorithm: String,
        hashAlgorithm: String
    ): Bool
}

pub contract Crypto {

    pub struct SignatureAlgorithm {
        pub let name: String

        init(name: String) {
            self.name = name
        }
    }

    // ECDSA_P256 is Elliptic Curve Digital Signature Algorithm (ECDSA) on the NIST P-256 curve
    pub let ECDSA_P256: SignatureAlgorithm

    // ECDSA_Secp256k1 is Elliptic Curve Digital Signature Algorithm (ECDSA) on the secp256k1 curve
    pub let ECDSA_Secp256k1: SignatureAlgorithm

    pub struct HashAlgorithm {
        pub let name: String

        init(name: String) {
            self.name = name
        }
    }

    // SHA2_256 is Secure Hashing Algorithm 2 (SHA-2) with a 256-bit digest
    pub let SHA2_256: HashAlgorithm

    // SHA3_256 is Secure Hashing Algorithm 3 (SHA-3) with a 256-bit digest
    pub let SHA3_256: HashAlgorithm

    pub struct PublicKey {
        pub let publicKey: [UInt8]
        pub let signatureAlgorithm: SignatureAlgorithm

        init(publicKey: [UInt8], signatureAlgorithm: SignatureAlgorithm) {
            self.publicKey = publicKey
            self.signatureAlgorithm = signatureAlgorithm
        }
    }

    pub struct KeyListEntry {
        pub let keyIndex: Int
        pub let publicKey: PublicKey
        pub let hashAlgorithm: HashAlgorithm
        pub let weight: UFix64
        pub let isRevoked: Bool

        init(
            keyIndex: Int,
            publicKey: PublicKey,
            hashAlgorithm: HashAlgorithm,
            weight: UFix64,
            isRevoked: Bool
        ) {
            self.keyIndex = keyIndex
            self.publicKey = publicKey
            self.hashAlgorithm = hashAlgorithm
            self.weight = weight
            self.isRevoked = isRevoked
        }
    }

    pub struct KeyList {

        priv let entries: [KeyListEntry]

        init() {
            self.entries = []
        }

        // Adds a new key with the given weight
        pub fun add(
            _ publicKey: PublicKey,
            hashAlgorithm: HashAlgorithm,
            weight: UFix64
        ): KeyListEntry {

            let keyIndex = self.entries.length
            let entry = KeyListEntry(
                keyIndex: keyIndex,
                publicKey: publicKey,
                hashAlgorithm: hashAlgorithm,
                weight: weight,
                isRevoked: false
            )
            self.entries.append(entry)
            return entry
        }

        // Returns the key at the given index, if it exists.
        // Revoked keys are always returned, but they have `isRevoked` field set to true
        pub fun get(keyIndex: Int): KeyListEntry? {
            if keyIndex >= self.entries.length {
                return nil
            }

            return self.entries[keyIndex]
        }

        // Marks the key at the given index revoked, but does not delete it
        pub fun revoke(keyIndex: Int) {
            if keyIndex >= self.entries.length {
                return
            }
            let currentEntry = self.entries[keyIndex]
            self.entries[keyIndex] = KeyListEntry(
                keyIndex: currentEntry.keyIndex,
                publicKey: currentEntry.publicKey,
                hashAlgorithm: currentEntry.hashAlgorithm,
                weight: currentEntry.weight,
                isRevoked: true
            )
        }

        pub fun isValid(
            signatureSet: [KeyListSignature],
            signedData: [UInt8]
        ): Bool {

            var validWeights: UFix64 = 0.0

            let seenKeyIndices: {Int: Bool} = {}

            for signature in signatureSet {

                // Ensure the key index is valid

                if signature.keyIndex >= self.entries.length {
                    return false
                }

                // Ensure this key index has not already been seen

                if seenKeyIndices[signature.keyIndex] ?? false {
                    return false
                }

                // Record the key index was seen

                seenKeyIndices[signature.keyIndex] = true

                // Get the actual key

                let key = self.entries[signature.keyIndex]

                // Ensure the key is not revoked

                if key.isRevoked {
                    return false
                }

                // Ensure the signature is valid

                if !Crypto.signatureVerifier.verify(
                    signature: signature.signature,
                    tag: Crypto.domainSeparationTagFlowUser,
                    signedData: signedData,
                    publicKey: key.publicKey.publicKey,
                    signatureAlgorithm: key.publicKey.signatureAlgorithm.name,
                    hashAlgorithm:key.hashAlgorithm.name
                ) {
                    return false
                }

                validWeights = validWeights + key.weight
            }

            return validWeights >= 1.0
        }
    }

    pub struct KeyListSignature {
        pub let keyIndex: Int
        pub let signature: [UInt8]

        pub init(keyIndex: Int, signature: [UInt8]) {
            self.keyIndex = keyIndex
            self.signature = signature
        }
    }

    priv let domainSeparationTagFlowUser: String

    priv let signatureVerifier: {SignatureVerifier}

    init(signatureVerifier: {SignatureVerifier}) {

        self.signatureVerifier = signatureVerifier

        // Initialize constants

        self.ECDSA_P256 = SignatureAlgorithm(name: "ECDSA_P256")
        self.ECDSA_Secp256k1 = SignatureAlgorithm(name: "ECDSA_Secp256k1")

        self.SHA2_256 = HashAlgorithm(name: "SHA2_256")
        self.SHA3_256 = HashAlgorithm(name: "SHA3_256")

        self.domainSeparationTagFlowUser = "FLOW-V0.0-user"
    }
}

Definition of Done

  • Sema
    • Add built-in module
    • Declare types
    • Declare constants
  • Interpreter
    • Add built-in module
    • Implement types
    • Implement functions
  • Tests
    • Signature verification
    • Storage of types

Reject script functions and transactions with non-storable parameter types

Context

In #169 / #180 we introduced a way to determine if a type can be stored.

The parameter types of script function and transactions must be storable / serializable, so reject script functions and transactions with non-storable parameter types.

Definition of Done

  • Runtime: Reject script functions and transactions with non-storable parameter types

BUG: Contract Interface conformance does not register

Instructions

When requiring a access(self) field in a resource in a contract interface, if the resource in the implementation has the same access control modifier, an error is reported. There should be no error.

Steps to Reproduce

  1. Use this contract:
pub contract interface ContractTypeConform {
    pub resource Res {
        access(self) var private: Int
    }
}

pub contract Example: ContractTypeConform {
    pub resource Res {
        access(self) var private: Int

        init () {
            self.private = 0
        }
    }
}
  1. See that the resource Res in Example does not match the interface according to the static checker.

Acceptance Criteria

The resource must conform correctly

Context

Making nft storage fields private in an NFT collection

BUG: Removing objects from a dictionary does not load value correctly.

Problem

Objects are not being loaded correctly from a dictionary after it has been stored.

Steps to Reproduce

  1. Pull the josh/bugFix branch from the NFT repo:
    https://github.com/onflow/flow-nft/tree/josh/bugFix
  2. Run go test -v in the nfttests directory.
  3. See that there is an error that says missing NFT
  4. We use the simple contract SimpleNFT.cdc. At deployment time, the contract withdraws and deposits token index 1 from the dictionary to make sure that is working. Then in the GenerateDestroyScript in nft_templates.go, we load the collection from storage and try to withdraw with causes the missing NFT error. We had also gotten the error from borrowing a reference to the collection.

Acceptance Criteria

This test case must pass.

Context

This makes it impossible to withdraw an NFT from a collection, so it blocks testing of the topshot contracts on the testnet

Transaction panics when comparing public capability to `nil`

Problem

When getting a public capability from an AuthAccount and comparing it to nil, the execution panics.

Steps to Reproduce

  1. Run this transaction:
transaction {
  prepare(acct: AuthAccount) {
    if acct.getCapability(/public/test) == nil {
      log("it works")
    }
  }
}
  1. See panic:
WARN[3754] โ—  Transaction reverted                       txID=fc64e8078cd493038a12372bfb8c2da1aae7b2310cc55a01a75bdb5c400c831d
WARN[3754] ERR [fc64e8] code execution failed: Execution failed:
unreachable
goroutine 206 [running]:
runtime/debug.Stack(0x4dfd0a0, 0x52594c0, 0xc002e203e0)
        runtime/debug/stack.go:24 +0x9d
github.com/onflow/cadence/runtime/errors.NewUnreachableError(...)
        github.com/onflow/[email protected]/runtime/errors/errors.go:44
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).testEqual(0xc002cb98c0, 0x5258e60, 0xc002e20400, 0x5259940, 0x6f83920, 0xc00361c378)
        github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:1730 +0x160
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).VisitBinaryExpression.func16(0x4dd9180, 0xc002e208c0, 0xc002e20980, 0xc00361c3f8)
        github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:1632 +0x67
github.com/onflow/cadence/runtime/trampoline.MapTrampoline.func1(0x4dd9180, 0xc002e208c0, 0xc002e205a0, 0x1339a7240524a740)
        github.com/onflow/[email protected]/runtime/trampoline/trampoline.go:50 +0x39
github.com/onflow/cadence/runtime/trampoline.FlatMap.FlatMap.func1(0x4dd9180, 0xc002e208c0, 0xc002e208c0, 0xc002e20960)
        github.com/onflow/[email protected]/runtime/trampoline/trampoline.go:123 +0x42
github.com/onflow/cadence/runtime/trampoline.FlatMap.FlatMap.func1(0x4dd9180, 0xc002e208c0, 0x4cf7fa0, 0xc002e20980)
        github.com/onflow/[email protected]/runtime/trampoline/trampoline.go:123 +0x42
github.com/onflow/cadence/runtime/trampoline.FlatMap.Resume.func1(0xc002e20960, 0x4cf7fa0)
        github.com/onflow/[email protected]/runtime/trampoline/trampoline.go:134 +0x37
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).runUntilNextStatement(0xc002cb98c0, 0x524a740, 0xc002e20960, 0x0, 0x0, 0xc002e20600)
        github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:585 +0x35
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).runAllStatements(0xc002cb98c0, 0x524a740, 0xc001dfb5a0, 0x1, 0x1)
        github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:595 +0x56
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).InvokeTransaction(0xc002cb98c0, 0x0, 0xc00070c1f0, 0x1, 0x1, 0x0, 0x0)
        github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:813 +0x137
github.com/onflow/cadence/runtime.(*interpreterRuntime).transactionExecutionFunction.func1(0xc002cb98c0, 0x0, 0x0, 0xc00361c710, 0xc00361c710)
        github.com/onflow/[email protected]/runtime/runtime.go:390 +0x575
github.com/onflow/cadence/runtime.(*interpreterRuntime).interpret.func1()
        github.com/onflow/[email protected]/runtime/runtime.go:191 +0xa4
github.com/onflow/cadence/runtime.reportMetric(0xc00361c838, 0x5269660, 0xc002c1e0d0, 0xc00361c820)
        github.com/onflow/[email protected]/runtime/runtime.go:97 +0xf3
github.com/onflow/cadence/runtime.(*interpreterRuntime).interpret(0x6f83920, 0x522db20, 0xc002146820, 0x5269660, 0xc002c1e0d0, 0xc002146840, 0xc0004c4d00, 0xc000138000, 0x7, 0xa, ...)
        github.com/onflow/[email protected]/runtime/runtime.go:185 +0x1d2
github.com/onflow/cadence/runtime.(*interpreterRuntime).ExecuteTransaction(0x6f83920, 0xc000020240, 0xb8, 0xc0, 0x6f83920, 0x0, 0x0, 0x5269660, 0xc002c1e0d0, 0x522db20, ...)
        github.com/onflow/[email protected]/runtime/runtime.go:298 +0x57c
github.com/dapperlabs/flow-go/engine/execution/computation/virtualmachine.(*virtualMachine).executeTransaction(...)
        github.com/dapperlabs/[email protected]/engine/execution/computation/virtualmachine/virtualMachine.go:68
github.com/dapperlabs/flow-go/engine/execution/computation/virtualmachine.(*blockContext).ExecuteTransaction(0xc001b02cc0, 0x52426c0, 0xc003094540, 0xc0001249c0, 0xc002d5e420, 0x2, 0x2, 0xc003094540, 0x0, 0x6f83920)
        github.com/dapperlabs/[email protected]/engine/execution/computation/virtualmachine/blockContext.go:135 +0x24d
github.com/dapperlabs/flow-emulator.(*Blockchain).executeNextTransaction.func1(0xc003094540, 0xc0001249c0, 0xc002b94e20, 0xc003402528, 0x795b008)
        github.com/dapperlabs/[email protected]/blockchain.go:586 +0xdd
github.com/dapperlabs/flow-emulator.(*pendingBlock).ExecuteNextTransaction(0xc001437560, 0xc002b95160, 0xc002c926a0, 0x8, 0x40164af)
        github.com/dapperlabs/[email protected]/pendingBlock.go:154 +0x10f
github.com/dapperlabs/flow-emulator.(*Blockchain).executeNextTransaction(0xc00038f480, 0x5242680, 0xc001b02cc0, 0xc00038f480, 0x5242680, 0xc001b02cc0)
        github.com/dapperlabs/[email protected]/blockchain.go:581 +0xaf
github.com/dapperlabs/flow-emulator.(*Blockchain).executeBlock(0xc00038f480, 0x10, 0xc002b952b8, 0x45eca17, 0x0, 0x0)
        github.com/dapperlabs/[email protected]/blockchain.go:548 +0x147
github.com/dapperlabs/flow-emulator.(*Blockchain).executeAndCommitBlock(0xc00038f480, 0xaa32d30b27b4b879, 0x8c19289c8b185885, 0x8693cef1332bb26c, 0x1573fbfa6b0a639f, 0xf93487d7f889e2d1, 0x7899273455a81143)
        github.com/dapperlabs/[email protected]/blockchain.go:667 +0x43
github.com/dapperlabs/flow-emulator.(*Blockchain).ExecuteAndCommitBlock(0xc00038f480, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        github.com/dapperlabs/[email protected]/blockchain.go:661 +0xa9
github.com/dapperlabs/flow-emulator/server.(*Backend).commitBlock(0xc001bf9a40)
        github.com/dapperlabs/[email protected]/server/backend.go:422 +0x4c
github.com/dapperlabs/flow-emulator/server.(*Backend).SendTransaction(0xc001bf9a40, 0x5249a80, 0xc000c95f50, 0xc000c95f80, 0xc001bf9a40, 0x5254f60, 0xc002bf3ec0)
        github.com/dapperlabs/[email protected]/server/backend.go:86 +0x8e5
github.com/onflow/flow/protobuf/go/flow/access._AccessAPI_SendTransaction_Handler.func1(0x5249a80, 0xc000c95f50, 0x4e64f20, 0xc000c95f80, 0x21, 0xc002800aa0, 0x0, 0xc002c9dae8)
        github.com/onflow/flow/protobuf/go/[email protected]/access/access.pb.go:1800 +0x89
github.com/grpc-ecosystem/go-grpc-prometheus.(*ServerMetrics).UnaryServerInterceptor.func1(0x5249a80, 0xc000c95f50, 0x4e64f20, 0xc000c95f80, 0xc001b028c0, 0xc001b028e0, 0xc002c46b58, 0x410d828, 0x4e54080, 0xc000c95f50)
        github.com/grpc-ecosystem/[email protected]/server_metrics.go:107 +0xad
github.com/onflow/flow/protobuf/go/flow/access._AccessAPI_SendTransaction_Handler(0x4ee72c0, 0xc001bf9a40, 0x5249a80, 0xc000c95f50, 0xc004a4a180, 0xc0003e0360, 0x5249a80, 0xc000c95f50, 0xc002966000, 0x150)
        github.com/onflow/flow/protobuf/go/[email protected]/access/access.pb.go:1802 +0x14b
google.golang.org/grpc.(*Server).processUnaryRPC(0xc0003e49c0, 0x525ce80, 0xc0004a8480, 0xc0030d0100, 0xc000ac4270, 0x6f54de0, 0x0, 0x0, 0x0)
        google.golang.org/[email protected]/server.go:1082 +0x4fd
google.golang.org/grpc.(*Server).handleStream(0xc0003e49c0, 0x525ce80, 0xc0004a8480, 0xc0030d0100, 0x0)
        google.golang.org/[email protected]/server.go:1405 +0xd25
google.golang.org/grpc.(*Server).serveStreams.func1.1(0xc001b97340, 0xc0003e49c0, 0x525ce80, 0xc0004a8480, 0xc0030d0100)
        google.golang.org/[email protected]/server.go:746 +0xbb
created by google.golang.org/grpc.(*Server).serveStreams.func1
        google.golang.org/[email protected]/server.go:744 +0xa1

This does not cause an issue when trying to get the capability from storage

Acceptance Criteria

No panic

JSON-CDC decoder incorrectly handles unpadded Fix64 and UFix64 values

Problem

As per the JSON-CDC spec, fixed point numbers do not need to be encoded with trailing zeros after the decimal point: https://github.com/onflow/flow/blob/master/docs/json-cadence-spec.md#fixed-point-numbers

However, the encoding/json package only correctly decodes JSON-CDC Fix64 and UFix64 values if they contain exactly 8 digits after the decimal point.

For example, this value:

{
    "type": "Fix64",
    "value": "12.3"
}

is incorrectly decoded as 0.00000123.

Whereas this value:

{
    "type": "Fix64",
    "value": "12.30000000"
}

is correctly decoded as 12.3.

BUG: Runtime panic when deploying contracts

Problem

Got a runtime panic when trying to deploy contracts as part of automated tests

Steps to Reproduce

  1. Use this branch of the flow-ft repo: https://github.com/onflow/flow-ft/tree/josh/transactions

  2. This uses github.com/onflow/[email protected]
    github.com/dapperlabs/[email protected]
    github.com/dapperlabs/flow-go@30b3e2d5a5860c437e523921d08a97896b1e50e0
    github.com/onflow/[email protected]

  3. Go to lib/go/test/ and run go test -v

  4. See the runtime panic

Full Stack Trace

=== RUN   TestTokenDeployment
--- FAIL: TestTokenDeployment (0.33s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x70 pc=0x141a25c]

goroutine 36 [running]:
testing.tRunner.func1.1(0x1936360, 0x24f2d00)
	/usr/local/Cellar/go/1.14/libexec/src/testing/testing.go:941 +0x3d0
testing.tRunner.func1(0xc0001ccc60)
	/usr/local/Cellar/go/1.14/libexec/src/testing/testing.go:944 +0x3f9
panic(0x1936360, 0x24f2d00)
	/usr/local/Cellar/go/1.14/libexec/src/runtime/panic.go:967 +0x15d
github.com/onflow/cadence/runtime/interpreter.recoverErrors(0xc000674710)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:864 +0x15a
panic(0x1936360, 0x24f2d00)
	/usr/local/Cellar/go/1.14/libexec/src/runtime/panic.go:967 +0x15d
github.com/onflow/cadence/runtime/sema.(*CapabilityType).Unify(0xc0001930a0, 0x1d12660, 0xc0001930a0, 0xc000910a50, 0xc000541b80, 0x922, 0x42, 0x2d, 0x92a, 0x42, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/type.go:6652 +0x4c
github.com/onflow/cadence/runtime/sema.(*Checker).checkInvocationRequiredArgument(0xc0000d6300, 0xc0000ac2a0, 0x1, 0x1, 0x0, 0xc00057b540, 0xc000541b20, 0x1, 0x1, 0xc000910a50, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_invocation_expression.go:481 +0x28a
github.com/onflow/cadence/runtime/sema.(*Checker).checkInvocation(0xc0000d6300, 0xc0001e24e0, 0x1d15a00, 0xc000541a50, 0xc000541a50, 0x1, 0x0, 0x0, 0x0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_invocation_expression.go:380 +0x27f
github.com/onflow/cadence/runtime/sema.(*Checker).checkInvocationExpression.func3(...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_invocation_expression.go:97
github.com/onflow/cadence/runtime/sema.(*Checker).checkInvocationExpression(0xc0000d6300, 0xc0001e24e0, 0x0, 0x0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_invocation_expression.go:107 +0x7af
github.com/onflow/cadence/runtime/sema.(*Checker).VisitInvocationExpression(0xc0000d6300, 0xc0001e24e0, 0xc0000d6300, 0x2f153e8)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_invocation_expression.go:27 +0x3f
github.com/onflow/cadence/runtime/ast.(*InvocationExpression).AcceptExp(...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/expression.go:339
github.com/onflow/cadence/runtime/ast.(*InvocationExpression).Accept(...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/expression.go:335
github.com/onflow/cadence/runtime/sema.(*Checker).VisitCreateExpression(0xc0000d6300, 0xc0002a1280, 0x0, 0x0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_create_expression.go:37 +0xd8
github.com/onflow/cadence/runtime/ast.(*CreateExpression).AcceptExp(...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/expression.go:646
github.com/onflow/cadence/runtime/ast.(*CreateExpression).Accept(0xc0002a1280, 0x1d2e1c0, 0xc0000d6300, 0xc000671458, 0x142aaf9)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/expression.go:642 +0x5f
github.com/onflow/cadence/runtime/sema.(*Checker).VisitUnaryExpression(0xc0000d6300, 0xc0003a6870, 0xc0000d6300, 0x2f153e8)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_unary_expression.go:28 +0x62
github.com/onflow/cadence/runtime/ast.(*UnaryExpression).AcceptExp(...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/expression.go:507
github.com/onflow/cadence/runtime/ast.(*UnaryExpression).Accept(0xc0003a6870, 0x1d2e1c0, 0xc0000d6300, 0xc000671560, 0x100c1ea)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/expression.go:503 +0x62
github.com/onflow/cadence/runtime/sema.(*Checker).VisitReturnStatement(0xc0000d6300, 0xc0002d7d00, 0x0, 0x0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_return_statement.go:56 +0x292
github.com/onflow/cadence/runtime/ast.(*ReturnStatement).Accept(0xc0002d7d00, 0x1d2e1c0, 0xc0000d6300, 0x1ced901, 0x1ced9a0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/statement.go:36 +0x3e
github.com/onflow/cadence/runtime/sema.(*Checker).visitStatements(0xc0000d6300, 0xc0003142d0, 0x1, 0x1)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_block.go:68 +0x14b
github.com/onflow/cadence/runtime/sema.(*Checker).visitFunctionBlock.func1()
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_function.go:350 +0x4b
github.com/onflow/cadence/runtime/sema.(*Checker).visitWithPostConditions(0xc0000d6300, 0x0, 0x1d12760, 0xc0007d72c0, 0xc0006717d8)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_function.go:308 +0x54
github.com/onflow/cadence/runtime/sema.(*Checker).visitFunctionBlock(0xc0000d6300, 0xc0002a12c0, 0xc0001729e0, 0x1)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_function.go:343 +0xcf
github.com/onflow/cadence/runtime/sema.(*Checker).checkFunction.func2()
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_function.go:158 +0x16f
github.com/onflow/cadence/runtime/sema.(*FunctionActivations).WithFunction(0xc0002a1560, 0xc00057b640, 0x3, 0xc000671928)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/function_activations.go:67 +0xfa
github.com/onflow/cadence/runtime/sema.(*Checker).checkFunction(0xc0000d6300, 0xc0004138b0, 0xc0003a6660, 0xc00057b640, 0xc0002a12c0, 0x1, 0x0, 0x1)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_function.go:141 +0x17a
github.com/onflow/cadence/runtime/sema.(*Checker).visitFunctionDeclaration(0xc0000d6300, 0xc0001e2540, 0xc000010001, 0x19559c0, 0xc000910900)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_function.go:77 +0x13d
github.com/onflow/cadence/runtime/sema.(*Checker).checkCompositeFunctions.func1(0xc0000d6300, 0xc0007d7180, 0xc000671a90)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_composite_declaration.go:1386 +0xa2
github.com/onflow/cadence/runtime/sema.(*Checker).checkCompositeFunctions(0xc0000d6300, 0xc0000ac2b0, 0x1, 0x1, 0xc0007d7180)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_composite_declaration.go:1394 +0x7d
github.com/onflow/cadence/runtime/sema.(*Checker).visitCompositeDeclaration(0xc0000d6300, 0xc000222780, 0x2)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_composite_declaration.go:115 +0x5ca
github.com/onflow/cadence/runtime/sema.(*Checker).VisitCompositeDeclaration(0xc0000d6300, 0xc000222780, 0x0, 0x0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/check_composite_declaration.go:28 +0x3e
github.com/onflow/cadence/runtime/ast.(*CompositeDeclaration).Accept(0xc000222780, 0x1d2e1c0, 0xc0000d6300, 0x2, 0x1054d3c)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/composite.go:41 +0x3b
github.com/onflow/cadence/runtime/sema.(*Checker).VisitProgram(0xc0000d6300, 0xc0001b8f20, 0x10896c6, 0x5f063b6d)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/checker.go:453 +0x417
github.com/onflow/cadence/runtime/ast.(*Program).Accept(...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/ast/program.go:53
github.com/onflow/cadence/runtime/sema.(*Checker).Check.func1()
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/checker.go:326 +0x3b
github.com/onflow/cadence/runtime.(*interpreterRuntime).parseAndCheckProgram.func3.1()
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:524 +0x24
github.com/onflow/cadence/runtime.reportMetric(0xc000673b00, 0x1d1c520, 0xc0000d6800, 0xc000673b10)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:104 +0x93
github.com/onflow/cadence/runtime.(*interpreterRuntime).parseAndCheckProgram.func3(0x1ced640, 0xc0002e1ce0, 0xc000315050)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:522 +0x97
github.com/onflow/cadence/runtime/sema.(*Checker).Check(0xc0000d6300, 0x1ced640, 0xc0002e1ce0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/sema/checker.go:329 +0x128
github.com/onflow/cadence/runtime.(*interpreterRuntime).parseAndCheckProgram(0xc0002499c0, 0xc0003d2a80, 0x935, 0x935, 0x1d1c520, 0xc0000d6800, 0x1ced640, 0xc0002e1ce0, 0xc000146a80, 0x8, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:540 +0x42d
github.com/onflow/cadence/runtime.(*interpreterRuntime).updateAccountCode(0xc0002499c0, 0x1d1c520, 0xc0000d6800, 0xc0004e4720, 0xc0003d2a80, 0x935, 0x935, 0xee5e8fa7c1d2fcf3, 0xc0002c0b90, 0x0, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:1080 +0x181
github.com/onflow/cadence/runtime.(*interpreterRuntime).newSetCodeFunction.func1(0x0, 0xc0002c0b90, 0x1, 0x1, 0xc00007c0c0, 0x1, 0x1, 0xc000410330, 0x1ced620, 0xc0004e4700, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:1032 +0x1fd
github.com/onflow/cadence/runtime/interpreter.HostFunctionValue.Invoke(...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/interpreter/function.go:155
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).functionValueInvocationTrampoline(0xc0000b5800, 0x1d0cf60, 0xc0002c0400, 0xc0002c0b40, 0x1, 0x1, 0xc00007c0c0, 0x1, 0x1, 0xc00007c0d0, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:2098 +0x311
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).VisitInvocationExpression.func1.1(0x1a1af60, 0xc0000de6c0, 0xc0002e16c0, 0x1339a72401cfeaa0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:2016 +0x2c9
github.com/onflow/cadence/runtime/trampoline.FlatMap.FlatMap.func1(0x1a1af60, 0xc0000de6c0, 0xc0000de6c0, 0xc0002e1c20)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/trampoline/trampoline.go:142 +0x42
github.com/onflow/cadence/runtime/trampoline.FlatMap.FlatMap.func1(0x1a1af60, 0xc0000de6c0, 0x18df080, 0xc0002e1c40)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/trampoline/trampoline.go:142 +0x42
github.com/onflow/cadence/runtime/trampoline.FlatMap.Resume.func1(0xc0002e1c20, 0x18df080)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/trampoline/trampoline.go:154 +0x37
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).runUntilNextStatement(0xc0000b5800, 0x1cfeaa0, 0xc0002e1c20, 0x0, 0x0, 0xc0002e1720)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:608 +0x35
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).runAllStatements(0xc0000b5800, 0x1cfeaa0, 0xc00000e160, 0x3, 0x4)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:620 +0x56
github.com/onflow/cadence/runtime/interpreter.(*Interpreter).InvokeTransaction(0xc0000b5800, 0x0, 0xc00004cec0, 0x3, 0x4, 0x0, 0x0)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/interpreter/interpreter.go:853 +0x118
github.com/onflow/cadence/runtime.(*interpreterRuntime).transactionExecutionFunction.func1(0xc0000b5800, 0x0, 0x0, 0x2854a17800472850, 0x5f063b6d)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:400 +0x183
github.com/onflow/cadence/runtime.(*interpreterRuntime).interpret.func1()
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:232 +0xa4
github.com/onflow/cadence/runtime.reportMetric(0xc000472978, 0x1d1c520, 0xc0000d6800, 0xc000674960)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:104 +0x93
github.com/onflow/cadence/runtime.(*interpreterRuntime).interpret(0xc0002499c0, 0x1ced620, 0xc0004e4700, 0x1d1c520, 0xc0000d6800, 0xc0004e4720, 0xc0000d6900, 0xc000146380, 0x8, 0xc, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:226 +0x1d2
github.com/onflow/cadence/runtime.(*interpreterRuntime).ExecuteTransaction(0xc0002499c0, 0xc000654340, 0xce, 0xce, 0xc000715c80, 0x2, 0x2, 0x1d1c520, 0xc0000d6800, 0x1ced620, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/onflow/[email protected]/runtime/runtime.go:339 +0x57d
github.com/dapperlabs/flow-go/fvm.(*TransactionInvocator).Process(0x2536258, 0xc000520b30, 0x1d08d40, 0x24f51c0, 0x1cf36e0, 0xc0005241f0, 0x1ced4c0, 0xc0001ccd80, 0x0, 0x186a0, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/fvm/transaction.go:90 +0x272
github.com/dapperlabs/flow-go/fvm.(*TransactionProcedure).Run(0xc000356cb0, 0xc000520b30, 0x1d08d40, 0x24f51c0, 0x1cf36e0, 0xc0005241f0, 0x1ced4c0, 0xc0001ccd80, 0x0, 0x186a0, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/fvm/transaction.go:37 +0xe4
github.com/dapperlabs/flow-go/fvm.(*VirtualMachine).Run(...)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/fvm/fvm.go:29
github.com/dapperlabs/flow-emulator.(*Blockchain).executeNextTransaction.func1(0xc00057ae40, 0xc0000b5a40, 0xc000475230, 0xc0000d8ec8, 0x1000000016681e3)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/blockchain.go:613 +0x1c7
github.com/dapperlabs/flow-emulator.(*pendingBlock).ExecuteNextTransaction(0xc0001110e0, 0xc0004754a8, 0x1ced4c0, 0xc0001ccd80, 0x0)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/pendingBlock.go:148 +0x10f
github.com/dapperlabs/flow-emulator.(*Blockchain).executeNextTransaction(0xc0001ccd80, 0x1d08d40, 0x24f51c0, 0x1cf36e0, 0xc0005241f0, 0x1ced4c0, 0xc0001ccd80, 0x0, 0x186a0, 0xc000210620, ...)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/blockchain.go:606 +0xa7
github.com/dapperlabs/flow-emulator.(*Blockchain).executeBlock(0xc0001ccd80, 0xce, 0xc000715c80, 0x2, 0x2, 0x3b9ac9ff)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/blockchain.go:570 +0x20e
github.com/dapperlabs/flow-emulator.(*Blockchain).executeAndCommitBlock(0xc0001ccd80, 0xc000654340, 0xce, 0xce, 0xc000715c80, 0x2, 0x2)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/blockchain.go:694 +0x43
github.com/dapperlabs/flow-emulator.(*Blockchain).CreateAccount(0xc0001ccd80, 0xc000475f58, 0x1, 0x1, 0xc0006bca80, 0x935, 0xa80, 0x0, 0x0, 0x0)
	/Users/joshuahannan/go/pkg/mod/github.com/dapperlabs/[email protected]/blockchain.go:812 +0x393
github.com/onflow/flow-ft/lib/go/test.DeployTokenContracts(0xc0001ccd80, 0xc0001ccc60, 0xc000475f58, 0x1, 0x1, 0x0, 0x0, 0x0)
	/Users/joshuahannan/flow/flow-ft/lib/go/test/token_test.go:433 +0x29e
github.com/onflow/flow-ft/lib/go/test.TestTokenDeployment(0xc0001ccc60)
	/Users/joshuahannan/flow/flow-ft/lib/go/test/token_test.go:24 +0xeb
testing.tRunner(0xc0001ccc60, 0x1bd0c80)
	/usr/local/Cellar/go/1.14/libexec/src/testing/testing.go:992 +0xdc
created by testing.(*T).Run
	/usr/local/Cellar/go/1.14/libexec/src/testing/testing.go:1043 +0x357
exit status 2

Improve error handling pattern between runtime and host environment

Issue To Be Solved

There are currently inconsistencies in the way errors are passed from the host environment to the runtime and back (through runtime.Interface).

Errors can be classified into three categories:

  • User errors: recoverable errors that occur inside a Cadence program (user space) (i.e. invalid syntax, division by zero)
  • Fatal errors: unrecoverable errors that are unexpected during the execution of a Cadence program (i.e. ledger database failure, implementation bug)
    • Panics: technically still a fatal error, but do not follow the same control flow as an error value

User and fatal errors can originate from both the runtime.Interface implementation (host environment) and from inside the runtime. However, we currently lack a well-defined pattern for differentiating between user errors and fatal errors that originate from the host environment.

Add value encoding to the standard library

Issue To Be Solved

With the introduction of the Crypto built-in package, there is now a use case for converting arbitrary Cadence values into a serialized byte array, which can then be hashed and verified against a signature.

This encoding format should be secure and well-defined, allowing users to encode values in an external environment (i.e. Go, JavaScript) and expect Cadence to produce the same results.

This encoding format may only need to support Cadence value types (i.e. no resources).

Possible Solution A

Expose an Encoding.RLP package as part of the Cadence standard library.

  • Simple API (i.e. RLP.Encode(value: AnyStruct))

Possible Solution B

Add a toBytes method to value types that produces a consistent byte-wise encoding.

  • E.g. let myIntBytes = myInt.toBigEndianBytes()

Reject scripts with non-storable return type

Context

In #169 / #180 we introduced a way to determine if a type can be stored.

The return type of a script must be storable / serializable, so reject functions with a non-storable return type.

Definition of Done

  • Runtime: Reject scripts with a non-storable return type

Storage Querying API

Issue To Be Solved

A way to iterate over the storage to be able to list the resources owned by an account.

(Optional): Suggest A Solution

  • using a Cadence script:
    for entry in account.storageEntries { log(entry) }
  • using RPC:
    getAccount(โ€œ0x01")
    The response result can have a storage field with data in the cadence format (json with types)
  • Details of the technical implementation
  • Tradeoffs made in design decisions
  • Caveats and considerations for the future

If there are multiple solutions, please present each one separately. Save comparisons for the very end.)

(Optional): Context

Iโ€™m working on a marketplace and I was looking for a way to list all NFTs owned by an account.

Update documentation

Context

New features have been added to Cadence in the last few releases.
Update the documentation and describe the new features

Definition of Done

  • Querying block information
  • Crypto contract
  • Typed capabilities
  • Run-time Types
  • Addresses size (8 instead of 20 bytes)
  • Parameters for transactions and scripts
  • fun toString(): String was added for all number types and addresses
  • fun toBytes(): [UInt8] was added to Address
  • fun toBigEndianBytes(): [UInt8] was added to all number types.
  • Fields which have a non-storable type are now rejected:
    Non-storable types are:
    • Functions (e.g. ((Int): Bool))
    • Accounts (AuthAccount / PublicAccount)
    • Transactions
    • Void
  • String.decodeHex(): [Int] โ†’ String.decodeHex(): [UInt8]
  • AuthAccount.addPublicKey(publicKey: [Int]) โ†’ AuthAccount.addPublicKey(publicKey: [UInt8])
  • AuthAccount.setCode(code: [Int]) โ†’ AuthAccount.setCode(code: [UInt8])
  • Conformance check now allows subtype for return type
  • Type hierarchy
  • unsafeRandom
  • Account creation

Add high-level write callback

Context

Some embedders of Cadence, e.g. the Playground, need to get the high-level representation (i.e. cadence.Value, not low-level byte-encoded representation).

Add an additional callback that gets called in addition to the low-level write callback (SetValue).

Definition of Done

  • Add support for an optional function that gets called when all values are written. Pass a cadence.Value instead of a []byte.

cc @psiemens

Get the run-time type of an object

Issue To Be Solved

Using interfaces we can't check what type is really used at run-time, sometimes it's required to check a specific type. Need to know the full name of a type I'm working with.

(Optional): Suggest A Solution

I know you are working to add a new type Type, so maybe you can add something like fun getType(): Type and also a fun toString(): String to the Type if it doesn't exist now.
I'd expect to call it in the following way: obj.getType().toString().
The format of a name of a type can be for instance: T.{account_address}.{contract_name}.{type_name}

Define constants for CBOR keys

Context

The key indices used in the CBOR encoder and decoder can easily get out of sync.
Introduce constants that are used on both sides.

Definition of Done

  • Define constants for the keys in the CBOR encoder, e.g.:

    const (
      EncodedTypeValueType uint64 = 0
    )
    
    type encodedTypeValue struct {
      Type interface{} `cbor:"0,keyasint"`
    }
    
  • Use the key constants in the CBOR decoder, e.g.:

    decodedStaticType, err := d.decodeStaticType(encoded[EncodedTypeValueType])
    

BUG: Values are not being stored in dictionaries correctly when transferred

Problem

Values that are transferred from a dictionary in one account to another account are not being stored correctly, so that a transaction that tries to access that value in the second dictionary causes the runtime to panic.

Steps to Reproduce

  1. Test cases are in the bugFix branch of the NFT repo: https://github.com/onflow/flow-nft/tree/josh/bugFix
  2. Deploy a contract with a collection, create a collection in storage with an NFT inside of it
  3. Create an empty collection in another account
  4. Transfer the NFT from the first account to the second account
  5. Try to withdraw or borrow a reference to the NFT in the second account
  6. Panic

Acceptance Criteria

Runtime must not panic and value must be accessed correctly

Context

Blocking NFT contracts from working correctly

Multiple contracts per account

Context

Currently account code may only declare up to one contract, and multiple contract interfaces.

There is one function, fun AuthAccount.setCode(_ code: [UInt8], ... initializerArguments), which updates the account's code,
and (if any) instantiates the contract and stores it in the world state.

The function is used both for initial contract deployment and for contract updates.
For the latter use case, this means that the existing contract instance is overwritten / lost.

Update this API to add support for adding, updating, and removing multiple contracts and contract interfaces, independently.

Proposal

  • Add new types:

    • Contract:

      A contract that can be deployed to an account.
      The initializer checks the code and aborts if:

      • The code does not contain exactly one contract or contract interface
      • The contract or contract interface name in the code does not match the given name
      • The code/program is invalid
      pub struct Contract {
          pub let name: String
          pub let code: [UInt8]
      
          init(name: String, code: [UInt8])
      }
    • DeployedContract:

      A contract that is deployed at a given account.

      pub struct DeployedContract {
          pub let contract: Contract
          pub let address: Address
      }
    • AuthAccountContracts:

      The deployed contracts of an authorized account.
      Allows introspection, and also addition and removal.

      • fun add(contract: Contract, ... initializerArguments): DeployedContract

        • Adds the given contract to the account.
          The initializer arguments are passed to the initializer of the contract (if any)
        • Fails if a contract/contract interfaces with the name of the contract/contract interface n the given code already exists in the account
      • fun update__experimental(contract: Contract): DeployedContract

        • Experimental
        • Updates the code for the contract/contract interface in the given code in the account
        • Does not run the initializer of the contract/contract interface in the given code again. The contract instance in the world state stays as is
        • Fails if no contract/contract interface in the account with the name of the contract/contract interface in the given code exist
        • Returns the contract object for the updated contract
      • fun get(name: String): DeployedContract?

        • Returns the contract object for the contract/contract interface in the account with the given name, if any
        • Returns nil if no contract/contract interface with the given name exists in the account
      • fun delete(name: String): DeployedContract?

        • Deletes the contract/contract interface from the account which has the given name, if any
        • Returns the deleted contract object, if any
        • Returns nil if a contract/contract interface with the given name does not exist in the account
  • Add the following member to AuthAccount:

    let contracts: AuthAccountContracts

  • Add special function migrate to composites, the migration function, which is called automatically as part of AuthAccount.contracts.update:

    • For now, the function must know what version is being upgraded from,
      it is not passed any version information
    • migrate is a special function, like init and destroy;
      A user declaration fun migrate() won't be allowed.
      This prevents unintentionally implementing a migration function
    • migrate behaves similar to init

Future Possibilities

  • The type use for code, [UInt8], could be replaced with a dedicated Code type,
    e.g. to support other encodings
  • The code could be passed as a transaction argument, and support to import declarations from transaction arguments which have the type Code could be added. This would allow use of the contract after it is added/updated (the static analysis needs to have access to the type declarations in the passed code).
  • Add a destructor for contracts

Open Questions

  • What is the exact behaviour of migrate?
    • If initialization of constant fields is allowed, but the field existed in a previous version, then this could lead to accidental loss of resources
  • How are imports and dependencies between individual account code "pieces" handled?

Definition of Done

  • Sema, Interpreter, Runtime: Implement support for importing identifiers from a location from separate programs
  • Sema: Add new Account API
  • Interpreter, Runtime: Implement new Account API
  • Tests
  • Documentation

Require value for load/store to be storable

Context

In #169 / #180 we introduced a way to determine if a type can be stored.

The load/save functions of an account should only accept storable types.

Definition of Done

  • Sema: Add the requirement that the type parameter for the load/store functions of an account must be storable

Version programs

Context

Cadence programs should indicate in what version of Cadence they are written in.

Definition of Done

  • Parser:
    • Require the static annotation #version(_ version: String), e.g. #version("0.5") at the beginning of programs
    • AST: Add version string field to ast.Program
  • Tests
  • Documentation

BUG: Panics when storing a function, should statically reject

Problem

When trying to store a function in a smart contract, the runtime panics and crashes.

Steps to Reproduce

  1. Copy this contract:
pub contract Controller {

    pub var operator: AnyStruct?

    init(){  
        self.operator = fun(): Int{
            return 1
        }
    }
}
  1. Try to deploy the contract.
  2. See the runtime panic.

Acceptance Criteria

The checker should reject this

Definition of Done

The focus of this issue is just to not allow functions to be stored in fields.
In the future we will also have to reject more types, this is a starting place.

  • Interpreter: Add an allow list to member assignments; include all types, except function types
    • In CompositeValue.SetMember: check if valid value (StringValue, BoolValue, ...), recurse into nested value (e.g. arrays)
  • Checker: Remove rule that function types are not subtype of AnyStruct
  • Checker: Add an allow list: Fields can't have function type
    • In Checker.declareCompositeMembersAndValue:
      • after/before compositeType.Members = members:
        check check member.TypeAnnotation.Type is valid type (StringType, BoolType, ...),
        recurse into nested type (e.g. arrays)

Check type bound for parameterized type's type parameters

Context

Type parameters can have an optional type bound, e.g T<U: &Any>.

Check that the type argument is a subtype of the type bound.

Definition of Done

  • Sema: Check that all type arguments of an instantiation of a parameterized type are a subtype of the type parameter's type bound, if any.

Implement pretty print for Cadence

Issue To Be Solved

At the moment there is no pretty print solution for Cadence, which leads to simple mistakes - single quotes for String literals, for example - and waste of time, when you would reformat your code to make it more readable.

(Optional): Suggest A Solution

Prettier is a de-facto goto solution for pretty print in web development. And it have support for plugins. Main repository also have multiple implementations - Swift, for example - which can serve as inspiration and guidance to build one for Cadence.

Find join of types, improve inference

Context

Implement a function to return the least common supertype.

This improves type checking for:

  • Conditionals: instead of just returning the left type (type of true branch) and requiring the right type (else branch) to be the same
  • Array literals
  • Dictionary literals

See "Types and Programming Languages, 16.3 Joins and Meets"

In the following example y should be inferred to String?:

let x: String? = ""
let y = true ? nil : x 

Definition of Done

  • Sema:
    • Add function to find join of two or more types
    • Use join function for conditionals
    • Use join function for array literals
    • Use join function for dictionary literals
  • Tests
  • Documentation

Resource within an interface can't access variables of the interface

Problem

Consider the code:

pub contract interface FungibleTokenInterface {
    pub var paused: Bool
    ...
    ...
    pub resource interface Vault: Provider, Receiver, Balance { //same as in the spec
        pub var balance: UFix64

        pub fun withdraw(amount: UFix64): @Vault {
            pre {
                FungibleTokenInterface.paused == false: "Can't withdraw when function is paused"
               ...
            }
    }
}

Here I defined a contract variable in the interface called paused. But I can't call that in the pre-condition of the withdraw method on the Vault interface.

Deploying this contract gives the error- "can't access FungibleTokenInterface."

Context

I had to shift the pre condition code to my actual contract. I just think putting this in the interface makes things cleaner.

Emulator crash

Problem

Emulator is crashing

Steps to Reproduce

  1. use emulator in vs code
  2. use any contract that creates resources, for instance FungibleToken from playground
  3. create a resource and a public link, acct.link<&FungibleToken.Vault{FungibleToken.Receiver, FungibleToken.Balance}>(/public/MainReceiver, target: /storage/MainVault)
  4. execute script that returns a reference
pub fun main(): &FungibleToken.Vault{FungibleToken.Balance} {
    let acct1 = getAccount(0x01cf0e2f2f715450)
    let acct1ReceiverRef = acct1.getCapability(/public/MainReceiver)!
                          .borrow<&FungibleToken.Vault{FungibleToken.Balance}>()!
    return acct1ReceiverRef
  1. see thrown exception panic: cannot convert value of type *interpreter.StorageReferenceValue
  2. no other transaction/script can be executed after that

Acceptance Criteria

Such scripts shouldn't crash the emulator at run-time, but rather have to report an error.

Capture panics from runtime.Interface

Issue To Be Solved

Currently the runtime uses the wrapPanic function to capture panics that originate from method calls on the runtime.Interface object. The current implementation requires the caller to remember to wrap each call with wrapPanic, which is prone to bugs.

Suggest A Solution

Introduce an adapter for runtime.Interface that acts as a simple proxy to catch panics originating from the host environment.

Checker crashes when invoking a function of an undeclared variable

Problem

The following program crashes the checker:

let x = y.isInstance(Type<Int>())

with

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x14d97ea]

goroutine 15 [running]:
testing.tRunner.func1.1(0x1742f40, 0x1fee2e0)
	/usr/local/Cellar/go/1.14.2_1/libexec/src/testing/testing.go:940 +0x2f5
testing.tRunner.func1(0xc0000cc7e0)
	/usr/local/Cellar/go/1.14.2_1/libexec/src/testing/testing.go:943 +0x3f9
panic(0x1742f40, 0x1fee2e0)
	/usr/local/Cellar/go/1.14.2_1/libexec/src/runtime/panic.go:969 +0x166
github.com/onflow/cadence/runtime/sema.(*Checker).recordResourceInvalidation(0xc000aa8100, 0x1997ea0, 0xc00028f710, 0x0, 0x0, 0x2, 0x0)
	/Users/bastian/Documents/work/cadence/runtime/sema/checker.go:1411 +0x3a
github.com/onflow/cadence/runtime/sema.(*Checker).checkInvocationExpression(0xc000aa8100, 0xc000278960, 0x0, 0x0)
	/Users/bastian/Documents/work/cadence/runtime/sema/check_invocation_expression.go:158 +0x5e0
github.com/onflow/cadence/runtime/sema.(*Checker).VisitInvocationExpression(0xc000aa8100, 0xc000278960, 0xc000aa8100, 0x2795e10)
	/Users/bastian/Documents/work/cadence/runtime/sema/check_invocation_expression.go:27 +0x3f
github.com/onflow/cadence/runtime/ast.(*InvocationExpression).AcceptExp(...)
	/Users/bastian/Documents/work/cadence/runtime/ast/expression.go:339
github.com/onflow/cadence/runtime/ast.(*InvocationExpression).Accept(0xc000278960, 0x19b8640, 0xc000aa8100, 0xb, 0x2)
	/Users/bastian/Documents/work/cadence/runtime/ast/expression.go:335 +0x62
github.com/onflow/cadence/runtime/sema.(*Checker).visitVariableDeclaration(0xc000aa8100, 0xc0000d58c0, 0x0)
	/Users/bastian/Documents/work/cadence/runtime/sema/check_variable_declaration.go:43 +0xc2
github.com/onflow/cadence/runtime/sema.(*Checker).VisitVariableDeclaration(0xc000aa8100, 0xc0000d58c0, 0x10, 0xc0000bc3e8)
	/Users/bastian/Documents/work/cadence/runtime/sema/check_variable_declaration.go:27 +0x3a
github.com/onflow/cadence/runtime/ast.(*VariableDeclaration).Accept(0xc0000d58c0, 0x19b8640, 0xc000aa8100, 0x1, 0x0)
	/Users/bastian/Documents/work/cadence/runtime/ast/variable_declaration.go:51 +0x3e
github.com/onflow/cadence/runtime/sema.(*Checker).VisitProgram(0xc000aa8100, 0xc0000bc370, 0x0, 0x0)
	/Users/bastian/Documents/work/cadence/runtime/sema/checker.go:453 +0x417
github.com/onflow/cadence/runtime/ast.(*Program).Accept(...)
	/Users/bastian/Documents/work/cadence/runtime/ast/program.go:53
github.com/onflow/cadence/runtime/sema.(*Checker).Check.func1(...)
	/Users/bastian/Documents/work/cadence/runtime/sema/checker.go:326
github.com/onflow/cadence/runtime/sema.(*Checker).Check(0xc000aa8100, 0x1977580, 0x1960f70)
	/Users/bastian/Documents/work/cadence/runtime/sema/checker.go:331 +0x154
github.com/onflow/cadence/runtime/tests/checker.ParseAndCheckWithOptions(0xc0000cc7e0, 0x1852f87, 0x35, 0x0, 0x1977580, 0x1960f70, 0x0, 0x0, 0x0, 0x0, ...)
	/Users/bastian/Documents/work/cadence/runtime/tests/checker/utils.go:95 +0x232
github.com/onflow/cadence/runtime/tests/checker.ParseAndCheck(...)
	/Users/bastian/Documents/work/cadence/runtime/tests/checker/utils.go:36
github.com/onflow/cadence/runtime/tests/checker.TestCheckResourceMoveMemberInvocation.func6(0xc0000cc7e0)
	/Users/bastian/Documents/work/cadence/runtime/tests/checker/resources_test.go:4510 +0x89
testing.tRunner(0xc0000cc7e0, 0x18998c8)
	/usr/local/Cellar/go/1.14.2_1/libexec/src/testing/testing.go:991 +0xdc
created by testing.(*T).Run
	/usr/local/Cellar/go/1.14.2_1/libexec/src/testing/testing.go:1042 +0x357

Notes

Discovered using the fuzzer.

The problem occurs when invoking a member of an undeclared variable

BUG: Variable Declarations are shadowed in for and while-loops

Problem

In a function, a variable can be declared in a subscope with the same name as another variable in the function, which shadows the previously declared variable. This shouldn't be allowed.

Steps to Reproduce

  1. Copy this contract

pub contract Nodes {
    init() {
        var node = 1

        var i = 1
        // are we supposed to be allowed to use a name that we've already used?
        while i < 10 {

            // which num is used for the assignment?
            var node = 3
            log(node)
            i = i + 1
        }
        log(node)
    }
}
  1. Deploy it and see that there are no errors.

Acceptance Criteria

Checker should report an error that the variable with the same name cannot be declared in a subscope.

Make references non-storable

Context

In #169 / #180 we introduced a way to determine if a type can be stored.

Make references non-storable. Contracts should use capabilities instead.

Definition of Done

  • Checker: Make references non-storable

Notes

โš ๏ธ Ensure the change is backwards compatible with current contracts

Standardizing Resouce paths

So assets/tokens etc. are stored locally on an account's storage as a resource and not on a smart contract. Also, 2 resources can't have the same path.

So are we expecting users of Flow to not just remember their account address and private key but also where they store what resource?

Creating some kind of resource standard (and hoping that users comply) wouldn't work because what if they already had some resource stored there, or if a malicious user poses as my erc20 token and convinces the user to store it at that particular resource?

Storing a database table of the resource path for each account that uses my contract is also hard because as a developer, how will I know who is using my smart contract, until the event on the SC is fired.

1 idea that may work is to block certain resource paths on ALL accounts.
So for the flow token, what if you block "`/storage/FlowToken" everywhere. And do this is for every SC created which deals with assets.
And there is a community-based GitHub repo that shows which resource paths are blocked for which asset.

Doing this allows automation too. Now I can automatically create a link from storage to the public domain for each account allowing anyone to seamlessly send tokens to someone else.

Missing return value in return statement is not reported

Problem

If a function has a non-Void return type, the return statements in the function must have a return value.
However, currently no error is reported when the a return statement has no value.

Steps to Reproduce

The following program is invalid, because the return statement has no return value, but no error is reported:

fun test(): Int {
    return
}

Acceptance Criteria

  • An error should be reported

Version serialized data

Context

We might update the serialization format in the future.
Future-proof the current serialization format by adding a magic string with a version.

Definition of Done

  • Runtime: Add a magic string prefix with a version to the serialized data

Improve `ExpectCheckerErrors` to provide better error message

Issue To Be Solved

In our tests, we use ExpectCheckerErrors to check expected errors from the checker.

However when there are more or less expected errors then then actual errors, it would print error message like this:

    --- FAIL: TestRuntimeTransactionTopLevelDeclarations/transaction_with_resource (0.00s)
        utils.go:110:
                Error Trace:    utils.go:110
                                                        runtime_test.go:3236
                Error:          "[resource declarations are not valid at the top-level]" should have 2 item(s), but has 1
                Test:           TestRuntimeTransactionTopLevelDeclarations/transaction_with_resource

It doesn't tell what error was missing.

And when we expect no checker error, but actually had some, the currently error message only prints "Checking failed". And we have to use cmd.PrettyPrintError to print the detailed message.

It would be great if

  • when there are more expected errors then actual errors, it could print the missing expected errors
  • when there are no expected errors but actual there is, then print the actual error

Flow built-in event IDs include "S" prefix

Problem

The following event IDs are now emitted with a "S" prefix, which introduces a breaking change for downstream Flow SDKs.

  • S.flow.AccountCreated
  • S.flow.AccountKeyAdded
  • S.flow.AccountKeyRemoved
  • S.flow.AccountCodeUpdated

https://github.com/onflow/cadence/blob/master/runtime/stdlib/flow_builtin.go#L224-L246

Currently the VM uses the type ID produced by Cadence to index events, and users can query for events using these IDs. It may be the case that the VM should sanitize these IDs, rather than using the exact ID that Cadence produces.

Proposal for Cadence Repo organization

Issue To Be Solved

We've been talking about how we like cadence projects to be organized in github repos and have come up with a proposal that could use some feedback. The ways that out projects are currently organized is not very good and makes it seem like more of a Go project than cadence project, so we decided to change the hierarchy to put the cadence files more in the front.

Suggest A Solution

Here is our proposal:

contracts/ contains the cadence smart contract source code
transactions/ contains the scripts and transactions that are used to interact with the smartcontracts
lib/go, lib/js, etc contains language specific tools and packages for interacting with the smart contracts. These can include packages to return formatted transactions, contracts, and tests.

Within the lib/go/ directory, we have broken up it into 3 packages:

contracts: package for getting the text of the contracts in a repo, replacing some names and fields for customization
templates: packages for returning common transaction templates for the smart contracts. Uses the transaction templates in transactions/ to construct them.
test: contains all the automated test related code for testing your smart contract

This is still a work in progress, so please give feedback about the structure of the repo, the package organization, and whatever else you feel is important.

Inconsistent representation of byte arrays

Problem

The newly added toBytes and toBigEndianBytes methods return byte arrays typed as [UInt8], whereas the Crypto contract accepts public keys, signatures and messages typed as [Int]. To support compatibility between these APIs, the types should be consistent.

[UInt8] is more correct -- is there any reason not to update all existing byte array representations to be typed this way?

Add `borrow!/borrow? ... [as ...]` syntax

Context

It was suggested that in addition/instead of borrow<T>() function calls,
the dedicated syntax borrow!/borrow? ... [as ...] might be more readable and explicit.

Definition of Done

  • Parser: Add rule
  • Sema: Check
  • Interpreter: Interpret like borrow call
  • Tests
  • Documentation

JSON Serialization for AST

Context

To be able to process the AST outside of Go, for example to visualize it in an AST explorer, or use it for pretty-printing, the JSON representation must be improved:

  • Type information is necessary, e.g. to distinguish a boolean from a nil expression
  • Position information must be eagerly included. The internal representation computes it sometimes from child elements

Definition of Done

Implement and test json.MarshalJSON for the following types, adding a Type property where the element is polymorphic (e.g. expressions), and position information as StartPos and EndPos properties:

  • Access
  • Argument
  • Block
  • FunctionBlock
  • Condition
  • CompositeDeclaration
  • FieldDeclaration
  • ConditionKind
  • BoolExpression
  • NilExpression
  • StringExpression
  • IntegerExpression
  • FixedPointExpression
  • ArrayExpression
  • DictionaryExpression
  • IdentifierExpression
  • InvocationExpression
  • MemberExpression
  • IndexExpression
  • ConditionalExpression
  • UnaryExpression
  • BinaryExpression
  • FunctionExpression
  • CastingExpression
  • CreateExpression
  • DestroyExpression
  • ReferenceExpression
  • ForceExpression
  • PathExpression
  • FunctionDeclaration
  • SpecialFunctionDeclaration
  • ImportDeclaration
  • Identifier
  • IdentifierLocation
  • StringLocation
  • AddressLocation
  • InterfaceDeclaration
  • Members
  • Operation
  • Parameter
  • ParameterList
  • Program
  • ReturnStatement
  • BreakStatement
  • ContinueStatement
  • IfStatement
  • WhileStatement
  • ForStatement
  • EmitStatement
  • AssignmentStatement
  • SwapStatement
  • ExpressionStatement
  • TransactionDeclaration
  • Transfer
  • TransferOperation
  • TypeAnnotation
  • NominalType
  • OptionalType
  • VariableSizedType
  • ConstantSizedType
  • DictionaryType
  • FunctionType
  • ReferenceType
  • RestrictedType
  • InstantiationType
  • VariableDeclaration
  • VariableKind
  • DeclarationKind
  • CompositeKind
  • PragmaDeclaration

Ensure `Type` value is storable

Context

We've added the Type type and value. Make sure it can be saved to and loaded from storage.

Definition of Done

  • Interpreter: Ensure TypeValue is storable

Release v0.5

Context

Definition of Done

  • Review and merge outstanding PRs
  • Tag and release
  • Write release notes

Events are non-storable

Context

In #169 / #180 we introduced a way to determine if a type can be stored.

Events are not storable.

Definition of Done

  • Checker: Make events non-storable

Inconsistent behaviour of assert satement

Problem

The assert statement is behaving in a strange way in v0.5.0-beta1.

This script will panic due to the failed assertion:

pub fun main(): Int {
  assert(1 == 2)
  return 42
}

However, this script will return successfully with a value of 42:

pub fun main(): Int {
  assert 1 == 2
  return 42
}

Could this be a parser bug?

Type parameters and arguments for types

Context

The Capability type was introduced in the new storage interface.
If it could be made generic and have a type parameter, then the repeated explicit type argument for borrow call-sites could be removed.

Definition of Done

  • Parser: Allow programs to provide type arguments (T<U_1, ..., U_n>)
  • Sema:
    • Allow types to have type parameters
    • Make Capability generic, add type parameter
  • Tests
  • Documentation

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.