├── .gitmodules ├── .nvmrc ├── assets ├── test.txt ├── genesis.json ├── bitcoin.pdf ├── null.json ├── examples │ └── public │ │ └── fonts │ │ ├── aller-bold.eot │ │ ├── aller-bold.ttf │ │ ├── aller-bold.woff │ │ ├── aller-light.eot │ │ ├── aller-light.ttf │ │ ├── aller-light.woff │ │ ├── roboto-black.eot │ │ ├── roboto-black.ttf │ │ └── roboto-black.woff ├── bundles │ └── browser.js ├── peers.json ├── client.jade ├── widget.json ├── cli.jade ├── opcodes.js ├── chain.json ├── message.json ├── zone.json ├── i.json ├── z.json ├── entity.json ├── app.jade ├── docs.tmpl ├── options.json └── fabric.json ├── docs ├── README.md ├── stack.png ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ └── OpenSans-LightItalic-webfont.woff ├── company.md ├── overview.md ├── swap.md ├── stack.dot ├── scripts │ ├── linenumber.js │ └── prettify │ │ └── lang-css.js ├── your-first-blockchain.md ├── overview.dot ├── hello-world.md └── styles │ └── prettify-jsdoc.css ├── .envrc ├── index.d.ts ├── contracts ├── noise.dot ├── functions.js ├── test.c ├── pair.dot ├── trace.js ├── federation.minsc ├── simple.dot ├── federation.js ├── lightning-playnet.dot ├── distribution.js ├── chat.dot ├── test.js ├── node.js ├── mount.js ├── chat.js ├── classes.dot ├── figure-1.svg └── exchange.js ├── EXAMPLES.md ├── reports ├── README.md └── install.log ├── stores └── README.md ├── images ├── fabric-labs.png └── architecture.png ├── scripts ├── reset-stores.sh ├── bitcoin-get-balance.sh ├── bitcoin-get-mempool.sh ├── bitcoin-new-address.sh ├── bitcoin-get-height.sh ├── bitcoin-create-block.sh ├── bitcoin-create-transaction.sh ├── lightning-playnet.sh ├── swarm.sh ├── zmq.js ├── bitcoin.js ├── node.js ├── bitcoin-a.sh ├── bitcoin-b.sh ├── bitcoin-mainnet.sh ├── ast.js ├── browser.js ├── keygen.js ├── bitcoin-playnet.sh ├── keyloader.js ├── miner.js ├── schemata.js ├── benchmark.js ├── bitcoin-get-miner-address.sh ├── build.js ├── app.js ├── classtree.js ├── playnet.js ├── identity.js └── example.js ├── functions ├── hasActor.js ├── hasObject.js ├── hasTarget.js ├── _handleError.js ├── _handleMessage.js ├── _handleWarning.js ├── handleException.js ├── padDigits.js ├── json.js ├── _sortKeys.js ├── html.js └── _handleFabricMessage.js ├── DEPENDENCIES.md ├── examples ├── public │ └── fonts │ │ ├── aller-bold.eot │ │ ├── aller-bold.ttf │ │ ├── aller-bold.woff │ │ ├── aller-light.eot │ │ ├── aller-light.ttf │ │ ├── aller-light.woff │ │ ├── roboto-black.eot │ │ ├── roboto-black.ttf │ │ └── roboto-black.woff ├── cluster │ ├── cluster.dot │ ├── README.md │ ├── node-d.js │ ├── node-e.js │ ├── node-a.js │ ├── node-b.js │ └── node-c.js ├── config.json ├── README.md ├── p2pkh.js ├── chain.js ├── message.js ├── lightning.js ├── blockchain.js ├── cli.js ├── environment.js ├── bitcoin.js ├── witness.js ├── fabric.js ├── index.js ├── http.js ├── service.js ├── network.js ├── heartbeat.js └── game.js ├── tests ├── fixtures │ ├── filesystem │ │ └── SAMPLE.md │ ├── test.txt │ ├── collection.js │ └── web.js ├── fabric.script.js ├── fabric.resource.js ├── fabric.transaction.js ├── bitcoin.core.js ├── zmq.core.js ├── contracts │ ├── distribution.unit.js │ └── federation.unit.js ├── bitcoin │ ├── block.js │ └── transaction.js ├── fabric.worker.js ├── fabric.bech32.js ├── fabric.witness.js ├── fabric.entity.js ├── fabric.vector.js ├── schemata.js ├── fabric.federation.js ├── fabric.swarm.js ├── fabric.tree.js ├── fabric.identity.js ├── fabric.oracle.js ├── fabric.scribe.js ├── fabric.logger.js ├── fabric.reader.js ├── fabric.signer.js ├── fabric.state.js ├── fabric.weave.js ├── fabric.channel.js ├── fabric.capability.js ├── fabric.codec.js ├── fabric.contract.js ├── fabric.hkdf.js ├── fabric.transition.js ├── fabric.app.js ├── fabric.hash256.js ├── fabric.router.js └── fabric.stack.js ├── .editorconfig ├── ACCESSIBILITY.md ├── OWNERS ├── settings ├── node-a.json ├── node-b.json ├── test.json ├── deprecations.js ├── default.json ├── bitcoin.json ├── playnet.json └── local.js ├── schemata ├── index.js ├── actor.json ├── SpendMessage.json └── activity.json ├── REQUIREMENTS.md ├── types ├── signature.js ├── network.js ├── observer.js ├── lightning │ └── message.js ├── authority.js ├── instruction.js ├── label.js ├── typetree.js ├── challenge.js ├── validator.js ├── disk.js ├── bond.js ├── transaction.js ├── value.js ├── program.js ├── token.js ├── secret.js ├── path.js ├── component.js ├── script.js ├── bech32.js ├── bitcoin │ ├── block.js │ └── transaction.js ├── snapshot.js ├── document.js ├── queue.js ├── capability.js ├── ledger.js ├── worker.js ├── mempool.js ├── tree.js ├── block.js ├── stash.js ├── codec.js └── consensus.js ├── Dockerfile ├── services ├── txt.js └── local.js ├── jsdoc.json ├── SECURITY.md ├── .bookignore ├── CHANGELOG.md ├── book.json ├── webpack.config.js ├── tsconfig.json ├── default.nix ├── SERVICES.md ├── BUILD.md ├── index.html ├── CONTRACTS.md ├── .github └── workflows │ └── test.yaml ├── INSTALL.md ├── COPYING ├── LICENSE ├── fixtures.js ├── SUMMARY.md ├── .gitignore ├── ACTORS.md ├── SETTINGS.md ├── GOALS.md ├── index.js ├── semantic.json ├── BEST_PRACTICES.md ├── IDENTITY.md └── snippets └── sidechains.md /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.17.1 2 | -------------------------------------------------------------------------------- /assets/test.txt: -------------------------------------------------------------------------------- 1 | Hello, world. -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Basic Docs 2 | foo -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | export FABRIC_NETWORK=playnet 2 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@fabric/core'; 2 | -------------------------------------------------------------------------------- /contracts/noise.dot: -------------------------------------------------------------------------------- 1 | digraph NOISE { 2 | "PROTOCOL_INIT" 3 | } 4 | -------------------------------------------------------------------------------- /EXAMPLES.md: -------------------------------------------------------------------------------- 1 | - [Chain][chain] 2 | 3 | [chain]: examples/chain.html 4 | -------------------------------------------------------------------------------- /assets/genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": "TO FUTURES UNKNOWN" 3 | } 4 | -------------------------------------------------------------------------------- /docs/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/stack.png -------------------------------------------------------------------------------- /reports/README.md: -------------------------------------------------------------------------------- 1 | # Reports 2 | Various reports are kept in this directory. 3 | -------------------------------------------------------------------------------- /stores/README.md: -------------------------------------------------------------------------------- 1 | # Stores 2 | Contains data directories for long-term storage. 3 | -------------------------------------------------------------------------------- /assets/bitcoin.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/bitcoin.pdf -------------------------------------------------------------------------------- /images/fabric-labs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/images/fabric-labs.png -------------------------------------------------------------------------------- /images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/images/architecture.png -------------------------------------------------------------------------------- /scripts/reset-stores.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf stores/bitcoin-{a,b} 3 | mkdir stores/bitcoin-{a,b} 4 | -------------------------------------------------------------------------------- /contracts/functions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | 'OP_TEST': require('./test') 5 | }; 6 | -------------------------------------------------------------------------------- /functions/hasActor.js: -------------------------------------------------------------------------------- 1 | module.exports = function (state) { 2 | return (state.actor) ? true : false; 3 | } 4 | -------------------------------------------------------------------------------- /functions/hasObject.js: -------------------------------------------------------------------------------- 1 | module.exports = function (state) { 2 | return (state.object) ? true : false; 3 | } 4 | -------------------------------------------------------------------------------- /functions/hasTarget.js: -------------------------------------------------------------------------------- 1 | module.exports = function (state) { 2 | return (state.target) ? true : false; 3 | } 4 | -------------------------------------------------------------------------------- /DEPENDENCIES.md: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | - `bitcoind --version` >= `v0.21.0` 3 | - `lightningd --version` >= `v0.10.2` 4 | -------------------------------------------------------------------------------- /contracts/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main () { 4 | printf("Hello, World!\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /assets/null.json: -------------------------------------------------------------------------------- 1 | { 2 | "@id": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a", 3 | "@data": {} 4 | } 5 | -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /examples/public/fonts/aller-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/aller-bold.eot -------------------------------------------------------------------------------- /examples/public/fonts/aller-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/aller-bold.ttf -------------------------------------------------------------------------------- /examples/public/fonts/aller-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/aller-bold.woff -------------------------------------------------------------------------------- /examples/public/fonts/aller-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/aller-light.eot -------------------------------------------------------------------------------- /examples/public/fonts/aller-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/aller-light.ttf -------------------------------------------------------------------------------- /tests/fixtures/filesystem/SAMPLE.md: -------------------------------------------------------------------------------- 1 | # Sample Markdown File 2 | This file exists to serve as a sample for filesystem tests. 3 | -------------------------------------------------------------------------------- /tests/fixtures/test.txt: -------------------------------------------------------------------------------- 1 | --- 2 | name: test.txt 3 | title: Fabric Test Document 4 | encoding: utf8 5 | --- 6 | Hello, world! 7 | -------------------------------------------------------------------------------- /contracts/pair.dot: -------------------------------------------------------------------------------- 1 | digraph Pair { 2 | "A" -> "B" 3 | "B" -> "A" 4 | } 5 | -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /examples/public/fonts/aller-light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/aller-light.woff -------------------------------------------------------------------------------- /examples/public/fonts/roboto-black.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/roboto-black.eot -------------------------------------------------------------------------------- /examples/public/fonts/roboto-black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/roboto-black.ttf -------------------------------------------------------------------------------- /examples/public/fonts/roboto-black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/examples/public/fonts/roboto-black.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_size = 2 6 | indent_style = space 7 | insert_final_newline = true 8 | -------------------------------------------------------------------------------- /assets/examples/public/fonts/aller-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/aller-bold.eot -------------------------------------------------------------------------------- /assets/examples/public/fonts/aller-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/aller-bold.ttf -------------------------------------------------------------------------------- /assets/examples/public/fonts/aller-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/aller-bold.woff -------------------------------------------------------------------------------- /assets/examples/public/fonts/aller-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/aller-light.eot -------------------------------------------------------------------------------- /assets/examples/public/fonts/aller-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/aller-light.ttf -------------------------------------------------------------------------------- /assets/examples/public/fonts/aller-light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/aller-light.woff -------------------------------------------------------------------------------- /assets/examples/public/fonts/roboto-black.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/roboto-black.eot -------------------------------------------------------------------------------- /assets/examples/public/fonts/roboto-black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/roboto-black.ttf -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /functions/_handleError.js: -------------------------------------------------------------------------------- 1 | module.exports = async function _handleError (...data) { 2 | console.error('[FABRIC:ERROR]', ...data); 3 | }; 4 | -------------------------------------------------------------------------------- /assets/bundles/browser.js: -------------------------------------------------------------------------------- 1 | /******/ (() => { // webpackBootstrap 2 | /******/ "use strict"; 3 | /******/ 4 | /******/ 5 | /******/ })() 6 | ; -------------------------------------------------------------------------------- /assets/examples/public/fonts/roboto-black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martindale/fabric/HEAD/assets/examples/public/fonts/roboto-black.woff -------------------------------------------------------------------------------- /functions/_handleMessage.js: -------------------------------------------------------------------------------- 1 | module.exports = async function _handleMessage (...data) { 2 | console.log('[FABRIC:MESSAGE]', ...data); 3 | }; 4 | -------------------------------------------------------------------------------- /functions/_handleWarning.js: -------------------------------------------------------------------------------- 1 | module.exports = async function _handleWarning (...data) { 2 | console.warn('[FABRIC:WARNING]', ...data); 3 | }; 4 | -------------------------------------------------------------------------------- /docs/company.md: -------------------------------------------------------------------------------- 1 | Fabric, Inc. is a company founded to ensure critical open source projects in the 2 | Fabric community receive long-term support and maintenance. -------------------------------------------------------------------------------- /ACCESSIBILITY.md: -------------------------------------------------------------------------------- 1 | # Making Fabric Accessible 2 | Fabric aims to be an accessible codebase. 3 | 4 | ## Basic Principles 5 | 1. Prioritize legibility over cleverness 6 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | approvers: 2 | - martindale 3 | reviewers: 4 | - anandsuresh 5 | - chrisinajar 6 | - manojdv 7 | - melnx 8 | - naterchdrsn 9 | - victorwu 10 | -------------------------------------------------------------------------------- /examples/cluster/cluster.dot: -------------------------------------------------------------------------------- 1 | digraph Cluster { 2 | "A" -> "B" [dir="both"] 3 | "B" -> "C" [dir="both"] 4 | "C" -> { 5 | "D" 6 | "E" 7 | } [dir="both"] 8 | } -------------------------------------------------------------------------------- /functions/handleException.js: -------------------------------------------------------------------------------- 1 | module.exports = async function handleException (exception) { 2 | console.trace('[FABRIC:FUNCTIONS]', 'Exception:', exception); 3 | }; 4 | -------------------------------------------------------------------------------- /assets/peers.json: -------------------------------------------------------------------------------- 1 | [ 2 | "fabric.pub:7777", 3 | "quill.is:7779", 4 | "soundtrack.io:7780", 5 | "pantheon.is:7781", 6 | "maki.io:7782", 7 | "localhost:7778" 8 | ] 9 | -------------------------------------------------------------------------------- /contracts/trace.js: -------------------------------------------------------------------------------- 1 | module.exports = function OP_TRACE (obj = {}) { 2 | Error.captureStackTrace(obj, OP_TRACE); 3 | return `@\n${obj.stack.split('\n').slice(1).join('\n')}`; 4 | }; 5 | -------------------------------------------------------------------------------- /settings/node-a.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bitcoin A", 3 | "symbol": "BTCA", 4 | "authority": "http://ahp7iuGhae8mooBahFaYieyaixei6too:naiRe9wo5vieFayohje5aegheenoh4ee@localhost:18444" 5 | } 6 | -------------------------------------------------------------------------------- /settings/node-b.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bitcoin B", 3 | "symbol": "BTCB", 4 | "authority": "http://ahp7iuGhae8mooBahFaYieyaixei6too:naiRe9wo5vieFayohje5aegheenoh4ee@localhost:19444" 5 | } 6 | -------------------------------------------------------------------------------- /assets/client.jade: -------------------------------------------------------------------------------- 1 | fabric-application 2 | fabric-grid 3 | fabric-column 4 | fabric-message-list 5 | fabric-message-composer 6 | fabric-column 7 | fabric-peer-list 8 | -------------------------------------------------------------------------------- /functions/padDigits.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function padDigits (number, digits) { 4 | return Array(Math.max(digits - String(number).length + 1, 0)).join(0) + number; 5 | }; 6 | -------------------------------------------------------------------------------- /tests/fixtures/collection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | list: [ 5 | { id: 1, something: 1 }, 6 | { id: 2, something: 2 }, 7 | { id: 3, something: 3 } 8 | ] 9 | }; -------------------------------------------------------------------------------- /reports/install.log: -------------------------------------------------------------------------------- 1 | $ npm i 2 | 3 | added 688 packages, and audited 689 packages in 1m 4 | 5 | 75 packages are looking for funding 6 | run `npm fund` for details 7 | 8 | found 0 vulnerabilities 9 | -------------------------------------------------------------------------------- /schemata/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Actor = require('./actor'); 4 | 5 | module.exports = { 6 | definitions: { 7 | Actor: Actor 8 | }, 9 | version: 'v0.1.0-RC1' 10 | }; 11 | -------------------------------------------------------------------------------- /REQUIREMENTS.md: -------------------------------------------------------------------------------- 1 | # Requirements for Fabric Nodes 2 | The following requirements are necessary to run a Fabric node: 3 | 4 | 1. Fully up-to-date `bitcoind >= 0.21.1` 5 | 2. 166 MHz x86 CPU 6 | 3. 256 MB RAM 7 | -------------------------------------------------------------------------------- /contracts/federation.minsc: -------------------------------------------------------------------------------- 1 | $federation = 4 of [ pk(A), pk(B), pk(C), pk(D), pk(E) ]; 2 | $recovery = 2 of [ pk(F), pk(G), pk(I) ]; 3 | $timeout = older(3 months); 4 | 5 | likely@$federation || ($timeout && $recovery) 6 | -------------------------------------------------------------------------------- /scripts/bitcoin-get-balance.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoin-cli \ 3 | -regtest \ 4 | -rpcport=20444 \ 5 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 6 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 7 | getbalance 8 | -------------------------------------------------------------------------------- /scripts/bitcoin-get-mempool.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoin-cli \ 3 | -regtest \ 4 | -rpcport=20444 \ 5 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 6 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 7 | getmempoolinfo 8 | -------------------------------------------------------------------------------- /scripts/bitcoin-new-address.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoin-cli \ 3 | -regtest \ 4 | -rpcport=20444 \ 5 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 6 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 7 | getnewaddress 8 | -------------------------------------------------------------------------------- /types/signature.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class Signature extends Buffer { 4 | constructor (str, encoding) { 5 | super(str, encoding); 6 | 7 | return this; 8 | } 9 | } 10 | 11 | module.exports = Signature; 12 | -------------------------------------------------------------------------------- /assets/widget.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Widget", 3 | "properties": { 4 | "name": { "type": "String" , "maxLength": 100 } 5 | }, 6 | "routes": { 7 | "list": "/widgets", 8 | "view": "/widgets/:id" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/bitcoin-get-height.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoin-cli \ 3 | -regtest \ 4 | -rpcport=20444 \ 5 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 6 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 7 | getblockchaininfo 8 | -------------------------------------------------------------------------------- /functions/json.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Parse input to a JSON string. 3 | * @param {Object} [input] Any input object. 4 | * @returns {String} 5 | */ 6 | module.exports = function (input) { 7 | return JSON.stringify(input, null, ' '); 8 | }; 9 | -------------------------------------------------------------------------------- /contracts/simple.dot: -------------------------------------------------------------------------------- 1 | digraph Simple { 2 | rankdir = LR 3 | label = "\nFigure 1: A Simple Program" 4 | input -> output 5 | 6 | subgraph cluster_variables { 7 | label = "Δ" 8 | input 9 | output 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /types/network.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Circuit = require('./circuit'); 4 | 5 | class Network { 6 | constructor (settings = {}) { 7 | this.settings = Object.assign({}, settings); 8 | } 9 | } 10 | 11 | module.exports = Network; -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10 2 | WORKDIR /fabric 3 | 4 | # if package.json changes. Docker deploys auto-update 5 | COPY package.json /fabric 6 | RUN npm install 7 | RUN npm build 8 | COPY . ./fabric 9 | 10 | EXPOSE 9999 11 | CMD ["npm", "start"] 12 | -------------------------------------------------------------------------------- /docs/overview.md: -------------------------------------------------------------------------------- 1 | # Fabric Design Overview 2 | 3 | 4 | ``` 5 | n | 6 | 10 | 7 | 9 | 8 | 8 | 9 | 7 | 10 | 6 | 11 | 5 | 12 | 4 | 13 | 3 | 14 | 2 | 15 | 1 | 16 | 0______| 17 | block #| 18 | ``` 19 | -------------------------------------------------------------------------------- /contracts/federation.js: -------------------------------------------------------------------------------- 1 | const Actor = require('../types/actor'); 2 | const Block = require('../types/block'); 3 | 4 | module.exports = function OP_ADVANCE_BLOCK (input) { 5 | const actor = new Actor(input); 6 | return { 7 | input: actor 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /types/observer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const monitor = require('fast-json-patch'); 4 | 5 | class Observer { 6 | constructor (target) { 7 | this.observer = monitor.observe(target); 8 | return this; 9 | } 10 | } 11 | 12 | module.exports = Observer; 13 | -------------------------------------------------------------------------------- /services/txt.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Service = require('../types/service'); 4 | 5 | class TXT extends Service { 6 | constructor (config) { 7 | super(config); 8 | this.config = Object.assign({}, config); 9 | } 10 | } 11 | 12 | module.exports = TXT; 13 | -------------------------------------------------------------------------------- /types/lightning/message.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const FabricMessage = require('../message'); 4 | 5 | class LightningMessage extends FabricMessage { 6 | constructor (settings = {}) { 7 | super(settings); 8 | } 9 | } 10 | 11 | module.exports = LightningMessage; -------------------------------------------------------------------------------- /jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fabric/core", 3 | "chat": "https://chat.fabric.pub/#/room/#hub:fabric.pub", 4 | "source": "https://github.com/FabricLabs/fabric", 5 | "templates": { 6 | "default": { 7 | "layoutFile": "assets/docs.tmpl" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/bitcoin-create-block.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoin-cli \ 3 | -regtest \ 4 | -rpcport=20444 \ 5 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 6 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 7 | generatetoaddress 1 bcrt1qfzwjez0ralajwvd7gschlc3mw54qd0v57s5nuc 8 | -------------------------------------------------------------------------------- /scripts/bitcoin-create-transaction.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoin-cli \ 3 | -regtest \ 4 | -rpcport=20444 \ 5 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 6 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 7 | sendtoaddress bcrt1q7ft2mmxma3ec9qslaky35lgut6vstvk8n8avyw 1 8 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | Fabric makes an effort to maximize the security of default system. 3 | 4 | ## Objectives 5 | - Maximize the security of a default system 6 | - Minimize external dependencies 7 | 8 | ## Process 9 | 1. Before beginning work, execute `npm run reports` 10 | -------------------------------------------------------------------------------- /types/authority.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const HTTP = require('./http'); 4 | 5 | class Authority extends HTTP { 6 | constructor (configuration = {}) { 7 | super(configuration); 8 | this.config = configuration; 9 | } 10 | } 11 | 12 | module.exports = Authority; 13 | -------------------------------------------------------------------------------- /scripts/lightning-playnet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | lightningd \ 3 | --lightning-dir ./stores/lightning-playnet \ 4 | --network regtest \ 5 | --bitcoin-rpcport 20444 \ 6 | --bitcoin-rpcuser 'ahp7iuGhae8mooBahFaYieyaixei6too' \ 7 | --bitcoin-rpcpassword 'naiRe9wo5vieFayohje5aegheenoh4ee' 8 | -------------------------------------------------------------------------------- /assets/cli.jade: -------------------------------------------------------------------------------- 1 | screen 2 | grid 3 | box#history(label="History", border-type="line") 4 | form#form(keys="true") 5 | textbox#input 6 | button#submit(type="submit") 7 | box#instructions [ESCAPE] (2x) exit] 8 | box#controls(border-type="line", bottom="0", height="3") 9 | -------------------------------------------------------------------------------- /docs/swap.md: -------------------------------------------------------------------------------- 1 | # Swaps on Bitcoin 2 | Running an on-chain swap using a Bitcoin-based blockchain. 3 | 4 | ## Quick Start 5 | 0. `npm i` 6 | 1. Start the Bitcoin nodes: 7 | 1. `./scripts/bitcoin-a.sh` 8 | 2. `./scripts/bitcoin-b.sh` 9 | 2. Start the Fabric node: `node scripts/swap.js` 10 | -------------------------------------------------------------------------------- /examples/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "@id": "22f425c57636160a6bb8ca6f16bce748aaef2999260609f02db3f2a8c6e3bc80", 3 | "@comment": "All fields beginning with the `@`-byte are to be removed before serialization.", 4 | "@data": { 5 | "name": "@examples/config" 6 | }, 7 | "name": "@examples/config" 8 | } 9 | -------------------------------------------------------------------------------- /assets/opcodes.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | OP_ADD: function compute (input) { 3 | let a = this.stack.pop(); 4 | let b = this.stack.pop(); 5 | let sum = parseInt(a) + parseInt(b); 6 | return sum; 7 | }, 8 | OP_TRUE: function compute (input) { 9 | return true; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /types/instruction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Scribe = require('./scribe'); 4 | 5 | class Instruction extends Scribe { 6 | constructor (config) { 7 | super(config); 8 | this.config = Object.assign({}, config); 9 | return this; 10 | } 11 | } 12 | 13 | module.exports = Instruction; 14 | -------------------------------------------------------------------------------- /scripts/swarm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ORACLE_LISTEN_PORT=3000 4 | PEER_LISTEN_PORT=7777 5 | 6 | for i in 0 1 2 3 4 5 6 7 | do 8 | NAME=swarm${i} 9 | PORT=$(($ORACLE_LISTEN_PORT + $i)) 10 | PEER=$(($PEER_LISTEN_PORT + $i)) 11 | PORT=$port PEER_PORT=$peer NAME=$name node scripts/cli.js & 12 | done 13 | -------------------------------------------------------------------------------- /assets/chain.json: -------------------------------------------------------------------------------- 1 | { 2 | "@comment~": "Strip @ prefix.", 3 | "@comment~": "Remark: ~ signifies !Triage", 4 | "id": "local", 5 | "type": "PoW", 6 | "resources": { 7 | "Tablet": { 8 | "@quotation": "Well, isn't that a funny coincidence.", 9 | "challenge": "identity", 10 | "result": 1 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /assets/message.json: -------------------------------------------------------------------------------- 1 | { 2 | "~": "@id is a special field which always resolves to the hash of @data.", 3 | "@id": "77b022ebccdee0c6f15454b794d140fd52750d566996a934c9d0830ce39627f9", 4 | "@data": "Hello, world.", 5 | "@input": "\"Hello, world.\"", 6 | "@encoding": "json", 7 | "@challenge": "806dbdb19dc8cdd1e43e1fbdd4ef4f4df3c3aff7b7d94a3f51da2c9f61b8f18a" 8 | } 9 | -------------------------------------------------------------------------------- /tests/fabric.script.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('../'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/app', function () { 7 | 8 | describe('Script', function () { 9 | it('is available from @fabric/core', function () { 10 | assert.equal(Fabric.Script instanceof Function, true); 11 | }); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /tests/fabric.resource.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('../'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/resource', function () { 7 | describe('Resource', function () { 8 | it('is available from @fabric/core', function () { 9 | assert.equal(Fabric.Resource instanceof Function, true); 10 | }); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Fabric Examples 2 | This is a list of Fabric examples, which can help in building your application. 3 | 4 | To run the examples, try `npm run examples` from the command line and follow the 5 | instructions on the console. 6 | 7 | ## Simple Ledger 8 | 9 | ## Beating Heart 10 | 11 | ## Game World 12 | 13 | ## Basic Blockchain 14 | 15 | ## Network Simulator 16 | -------------------------------------------------------------------------------- /tests/fabric.transaction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('../'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/transaction', function () { 7 | describe('Transaction', function () { 8 | xit('is available from @fabric/core', function () { 9 | assert.equal(Fabric.Transaction instanceof Function, true); 10 | }); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /functions/_sortKeys.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a new {@link Object} with sorted properties. 3 | * @param {Object} [state] Object to sort. 4 | * @returns {Object} Re-sorted instance of `state` as provided. 5 | */ 6 | module.exports = function _sortKeys (state = {}) { 7 | return Object.keys(state).sort().reduce((obj, key) => { 8 | obj[key] = state[key]; 9 | return obj; 10 | }, {}); 11 | }; 12 | -------------------------------------------------------------------------------- /types/label.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Actor = require('./actor'); 4 | const Hash256 = require('./hash256'); 5 | 6 | class Label extends Actor { 7 | constructor (input = '') { 8 | super(input); 9 | if (typeof input != 'string') input = super.serialize(input); 10 | this._id = Hash256.digest(`@labels/${input}`); 11 | return this; 12 | } 13 | } 14 | 15 | module.exports = Label; 16 | -------------------------------------------------------------------------------- /assets/zone.json: -------------------------------------------------------------------------------- 1 | { 2 | "@special~": "JSON notoriously doesn't have comments, so pay attention.", 3 | "@comment~": "This is a User-controlled Zone in Verse.", 4 | "@id": "/", 5 | "@name": "zone", 6 | "@data": { 7 | "@type~": "Zone", 8 | "@comment~": "Isomorphic to RPG's Places.", 9 | "id": "/places/the-orbus", 10 | "universe": "the-multiverse", 11 | "state": {} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /types/typetree.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const DepTree = require('dependency-tree'); 4 | 5 | class TypeTree { 6 | constructor (settings = {}) { 7 | this.settings = Object.assign({}, settings); 8 | this.tree = null; 9 | return this; 10 | } 11 | 12 | _loadFile (name) { 13 | this.tree = DepTree({ 14 | filename: name 15 | }); 16 | } 17 | } 18 | 19 | module.exports = TypeTree; 20 | -------------------------------------------------------------------------------- /scripts/zmq.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ZMQ = require('../services/zmq'); 4 | 5 | async function main () { 6 | const zmq = new ZMQ(); 7 | zmq.on('log', function (msg) { 8 | console.log('log:', msg); 9 | }); 10 | await zmq.start(); 11 | } 12 | 13 | main().catch((exception) => { 14 | console.error('exception:', exception); 15 | }).then((output) => { 16 | console.log('output:', output); 17 | }); 18 | -------------------------------------------------------------------------------- /contracts/lightning-playnet.dot: -------------------------------------------------------------------------------- 1 | digraph LightningPlaynet { 2 | "alice" 3 | -> "bob" 4 | -> "carol" 5 | 6 | "bob" -> { 7 | "alice" 8 | "carol" 9 | } 10 | 11 | subgraph cluster_externals { 12 | label = "Alice's Domain" 13 | "alice" 14 | "Alice's Public Web Service" 15 | 16 | "Alice's Public Web Service" -> "alice" 17 | "alice" -> "Alice's Public Web Service" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/bitcoin.core.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // testing 4 | const assert = require('assert'); 5 | 6 | // Types 7 | const Bitcoin = require('../services/bitcoin'); 8 | 9 | describe('@fabric/core/services/bitcoin', function () { 10 | describe('Bitcoin', function () { 11 | it('should expose a constructor', function () { 12 | assert.equal(Bitcoin.constructor instanceof Function, true); 13 | }); 14 | }); 15 | }); -------------------------------------------------------------------------------- /tests/zmq.core.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Testing 4 | const assert = require('assert'); 5 | const ZMQ = require('../services/zmq'); 6 | 7 | describe('@fabric/core/services/zmq', function () { 8 | describe('ZMQ', function () { 9 | it('can create an instance', async function provenance () { 10 | const zmq = new ZMQ({ 11 | name: 'Test' 12 | }); 13 | 14 | assert.ok(zmq); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /types/challenge.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const State = require('./state'); 4 | 5 | class Challenge extends State { 6 | constructor (configuration) { 7 | super(configuration); 8 | } 9 | 10 | validate (state) { 11 | let output = state._sign(); 12 | if (output['@id'] === this['@id']) { 13 | return true; 14 | } else { 15 | return false; 16 | } 17 | } 18 | } 19 | 20 | module.exports = Challenge; 21 | -------------------------------------------------------------------------------- /assets/i.json: -------------------------------------------------------------------------------- 1 | { 2 | "@special~": "JSON notoriously doesn't have comments, so pay attention.", 3 | "@comment~": "The next value is the direction we'll be taking a 'step' in.", 4 | "@id": "?", 5 | "@name": "z", 6 | "@data": { 7 | "@type~": "IrrationalNumber", 8 | "id": "?#defines-state", 9 | "output": { 10 | "await": "Event", 11 | "@type~": "String", 12 | "id": "#wormhole" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /assets/z.json: -------------------------------------------------------------------------------- 1 | { 2 | "@special~": "JSON notoriously doesn't have comments, so pay attention.", 3 | "@comment~": "The next value is the direction we'll be taking a 'step' in.", 4 | "@id": "/", 5 | "@name": "z", 6 | "@data": { 7 | "@type~": "Entity", 8 | "@comment~": "This object is love.", 9 | "id": "/entities/dat-bot", 10 | "junk": "true", 11 | "entity": "dat boi", 12 | "deviation": "foo" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /scripts/bitcoin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Node = require('../types/node'); 4 | const Bitcoin = require('../services/bitcoin'); 5 | const settings = require('../settings/local'); 6 | 7 | async function main (input = {}) { 8 | const node = new Node({ service: Bitcoin, settings: input }); 9 | await node.start(); 10 | } 11 | 12 | main(settings).catch((E) => { 13 | console.trace('[ALERT]', 'Service threw exception:', E); 14 | }); 15 | -------------------------------------------------------------------------------- /scripts/node.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const settings = require('../settings/local'); 4 | const Node = require('../contracts/node'); 5 | 6 | async function main (input = {}) { 7 | return Node(input); 8 | } 9 | 10 | main(settings).catch((exception) => { 11 | console.error('[SCRIPTS:NODE]', 'Main Process Exception:', exception); 12 | }).then((output) => { 13 | console.log('[SCRIPTS:NODE]', 'Main Process Output:', output); 14 | }); 15 | -------------------------------------------------------------------------------- /scripts/bitcoin-a.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoind \ 3 | -regtest \ 4 | -server \ 5 | -datadir=./stores/bitcoin-a \ 6 | -port=18445 \ 7 | -rpcport=18444 \ 8 | -zmqpubrawblock=tcp://127.0.0.1:29100 \ 9 | -zmqpubrawtx=tcp://127.0.0.1:29100 \ 10 | -zmqpubhashtx=tcp://127.0.0.1:29100 \ 11 | -zmqpubhashblock=tcp://127.0.0.1:29100 \ 12 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 13 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' 14 | -------------------------------------------------------------------------------- /scripts/bitcoin-b.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoind \ 3 | -regtest \ 4 | -server \ 5 | -datadir=./stores/bitcoin-b \ 6 | -port=19445 \ 7 | -rpcport=19444 \ 8 | -zmqpubrawblock=tcp://127.0.0.1:29200 \ 9 | -zmqpubrawtx=tcp://127.0.0.1:29200 \ 10 | -zmqpubhashtx=tcp://127.0.0.1:29200 \ 11 | -zmqpubhashblock=tcp://127.0.0.1:29200 \ 12 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 13 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' 14 | -------------------------------------------------------------------------------- /types/validator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('./fabric'); 4 | 5 | class Validator extends Fabric { 6 | constructor (config) { 7 | super(config); 8 | 9 | async function main (input) { 10 | return input.pipe(this.stream); 11 | } 12 | 13 | this.process = main(); 14 | 15 | return this; 16 | } 17 | 18 | validate (input) { 19 | return true; 20 | } 21 | } 22 | 23 | module.exports = Validator; 24 | -------------------------------------------------------------------------------- /.bookignore: -------------------------------------------------------------------------------- 1 | aliases 2 | assets 3 | bundles 4 | components 5 | contracts 6 | dist 7 | functions 8 | lib 9 | resources 10 | scripts 11 | services 12 | settings 13 | snippets 14 | stores 15 | tests 16 | tools 17 | types 18 | .bookignore 19 | .gitignore 20 | .gitmodules 21 | .travis.yml 22 | constants.js 23 | COPYING 24 | Dockerfile 25 | index.js 26 | jsdoc.json 27 | LICENSE 28 | package-lock.json 29 | package.json 30 | semantic.json 31 | webpack.config.js 32 | -------------------------------------------------------------------------------- /schemata/actor.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://hub.fabric.pub/schemata/actor.schema.json", 4 | "title": "Actor", 5 | "description": "Any Fabric entity.", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The unique identifier for an actor", 10 | "type": "string" 11 | } 12 | }, 13 | "required": [ "id" ], 14 | "version": "0.0.0" 15 | } 16 | -------------------------------------------------------------------------------- /assets/entity.json: -------------------------------------------------------------------------------- 1 | { 2 | "@special~": "JSON notoriously doesn't have comments, so pay attention.", 3 | "@comment~": "This is an instance of a particular Type of Resource.", 4 | "@id": "/", 5 | "@name": "entity", 6 | "@data": { 7 | "@type~": "Entity", 8 | "@comment~": "Think of this like an on-grid actor.", 9 | "id": "/entities/the-orbus", 10 | "position": { 11 | "x": 0, 12 | "y": 0, 13 | "z": 0 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/stack.dot: -------------------------------------------------------------------------------- 1 | digraph Stack { 2 | "ready" -> "read" [label=" start (1)"] 3 | "read" -> "stack" [label=" push (2)"] 4 | "read" -> "parse tuple\n(⨯ = [𝜃 , i⨯])" [label="compute vector space"] 5 | 6 | "parse tuple\n(⨯ = [𝜃 , i⨯])" -> "stack" [label=" push (3)"] 7 | 8 | "stack" [shape=box] 9 | 10 | "compute" -> "stack" [label="write"] 11 | 12 | "stack" -> "compute" [label="read"] 13 | 14 | "read" 15 | 16 | "compute" -> "done" 17 | } 18 | -------------------------------------------------------------------------------- /scripts/bitcoin-mainnet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoind \ 3 | -server \ 4 | -txindex \ 5 | -dbcache=4000 \ 6 | -datadir=./stores/bitcoin-mainnet \ 7 | -zmqpubrawblock=tcp://127.0.0.1:29500 \ 8 | -zmqpubrawtx=tcp://127.0.0.1:29500 \ 9 | -zmqpubhashtx=tcp://127.0.0.1:29500 \ 10 | -zmqpubhashblock=tcp://127.0.0.1:29500 \ 11 | -rpcbind=127.0.0.1 \ 12 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 13 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' 14 | -------------------------------------------------------------------------------- /types/disk.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | class Disk { 6 | constructor (root) { 7 | this.type = 'Disk'; 8 | this.root = root || process.env.PWD; 9 | } 10 | 11 | exists (path) { 12 | let full = [this.root, path].join('/'); 13 | return fs.existsSync(full); 14 | } 15 | 16 | get (path) { 17 | let full = [this.root, path].join('/'); 18 | return require(full); 19 | } 20 | } 21 | 22 | module.exports = Disk; 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `@fabric/core` Changelog 2 | Recent changes to Fabric Core. 3 | 4 | ## 2023-04-01 5 | ### `v0.1.0-RC1` pre-release 6 | First pass at public playnet! Initial release candidate for the `v0.1.0` tag. 7 | 8 | **Notable Changes:** 9 | - **New Feature:** Fabric CLI — interact with Fabric using your terminal! 10 | - **New Classes:** 11 | - Actor 12 | - Channel 13 | - Message 14 | - Peer 15 | - Service 16 | 17 | ## 2022-01-25 18 | Initial changelog file. 19 | -------------------------------------------------------------------------------- /examples/p2pkh.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Fabric = require('../'); 4 | var fabric = new Fabric(); 5 | 6 | fabric.use('OP_CHECKSIG', function (sig) { 7 | console.log('computing with OP_CHECKSIG:', sig); 8 | return true; // ;) 9 | //return this.validateSignature(sig, 'test'); 10 | }); 11 | 12 | fabric.stack.push(''); 13 | fabric.stack.push(''); 14 | fabric.stack.push('OP_CHECKSIG'); 15 | 16 | fabric.compute(); 17 | 18 | console.log('test:', fabric); 19 | -------------------------------------------------------------------------------- /scripts/ast.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const Compiler = require('../types/compiler'); 5 | const target = process.argv[2] || './contracts/node.js'; 6 | const data = fs.readFileSync(target); 7 | 8 | async function main () { 9 | let compiler = Compiler._fromJavaScript(data); 10 | console.log('[SCRIPTS:AST]', compiler); 11 | } 12 | 13 | main().catch((exception) => { 14 | console.error('[SCRIPTS:AST]', 'Main Process Exception:', exception); 15 | }); 16 | -------------------------------------------------------------------------------- /functions/html.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Parse input to an HTML string. 3 | * @param {Object} [input] Any input object. 4 | * @returns {String} 5 | */ 6 | module.exports = function html (input) { 7 | 'use strict'; 8 | // @author: Fabric Labs 9 | // @access private 10 | const Actor = require('@fabric/core/types/actor'); 11 | try { 12 | const actor = new Actor(input); 13 | return actor.toHTML(); 14 | } catch (exception) { 15 | return 'Error!\n'; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /settings/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fabric/core", 3 | "description": "Application Resource Contract for the Fabric Execution Environment.", 4 | "fullnode": false, 5 | "language": "english", 6 | "network": "regtest", 7 | "mode": "full", 8 | "persistent": false, 9 | "port": 9898, 10 | "key": { 11 | "seed": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" 12 | }, 13 | "stack": [], 14 | "state": {}, 15 | "zmq": false 16 | } 17 | -------------------------------------------------------------------------------- /tests/contracts/distribution.unit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Distribution = require('../../contracts/distribution'); 5 | 6 | describe('@fabric/core/types/distribution', function () { 7 | describe('Distribution', function () { 8 | it('can smoothly create a new distribution', function () { 9 | const distribution = new Distribution(); 10 | assert.ok(distribution); 11 | assert.ok(distribution.id); 12 | }); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Fabric Labs", 3 | "title": "Fabric Developer's Handbook", 4 | "description": "Build & Run P2P Applications with Fabric", 5 | "language": "en", 6 | "plugins": [], 7 | "pluginsConfig": { 8 | "theme-api": { 9 | "theme": "dark" 10 | }, 11 | "edit-link": { 12 | "base": "https://github.com/FabricLabs/fabric/edit/master", 13 | "label": "Edit This Page" 14 | }, 15 | "scripts": { 16 | "files": ["./assets/fabric.min.js"] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/distribution.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Contract = require('../types/contract'); 4 | 5 | class Distribution extends Contract { 6 | constructor (settings = {}) { 7 | super(settings); 8 | 9 | this.settings = Object.assign({ 10 | state: { 11 | amounts: [], 12 | recipients: [] 13 | } 14 | }, settings); 15 | 16 | this._state = { 17 | content: this.settings.state 18 | }; 19 | 20 | return this; 21 | } 22 | } 23 | 24 | module.exports = Distribution; 25 | -------------------------------------------------------------------------------- /scripts/browser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Peer = require('../types/peer'); 4 | 5 | async function main () { 6 | const component = document.createElement('fabric-component'); 7 | component.peer = new Peer(); 8 | console.log('component:', component); 9 | document.appendChild(component); 10 | } 11 | 12 | main().catch((exception) => { 13 | console.error('[FABRIC:EDGE]', 'Main Process Error:', exception); 14 | }).then((output) => { 15 | console.log('[FABRIC:EDGE]', 'Main Process Output:', output); 16 | }); 17 | -------------------------------------------------------------------------------- /scripts/keygen.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Wallet = require('../types/wallet'); 4 | 5 | async function main () { 6 | const wallet = new Wallet(); 7 | const seed = await wallet._createSeed(); 8 | const keypair = await wallet.generateCleanKeyPair(); 9 | console.warn('[FABRIC:KEYGEN]', 'Key generated:', keypair); 10 | console.warn('[FABRIC:KEYGEN]', 'SEED:', seed); 11 | process.exit(); 12 | } 13 | 14 | main().catch((E) => { 15 | console.error('[FABRIC:KEYGEN]', 'Key generator threw Exception:', E); 16 | }); 17 | -------------------------------------------------------------------------------- /tests/bitcoin/block.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Block = require('../../types/bitcoin/block'); 5 | 6 | const settings = require('../../settings/test'); 7 | 8 | describe('@fabric/core/types/bitcoin/block', function () { 9 | it('is available from @fabric/core', function () { 10 | assert.equal(Block instanceof Function, true); 11 | }); 12 | 13 | it('creates an empty instance', function () { 14 | const block = new Block(); 15 | assert.ok(block); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /functions/_handleFabricMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Fabric Types 4 | const Message = require('../types/message'); 5 | 6 | // Define the _handleFabricMessage 7 | async function _handleFabricMessage (...data) { 8 | const message = Message.fromVector([...data]); // TODO: redefine... 9 | console.log('[FABRIC:MESSAGE]', message); 10 | } 11 | 12 | // CommonJS export 13 | // Example: 14 | // ```js 15 | // const _handleFabricMessage = require('@fabric/core/functions/_handleFabricMessage'); 16 | // ``` 17 | module.exports = _handleFabricMessage; 18 | -------------------------------------------------------------------------------- /tests/contracts/federation.unit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const settings = require('../../fixtures') 5 | const Federation = require('../../contracts/federation'); 6 | 7 | describe('@fabric/core/contracts/federation', function () { 8 | describe('Federation', function () { 9 | it('exists', function () { 10 | assert.ok(Federation); 11 | }); 12 | 13 | it('can execute', function () { 14 | const federation = Federation(settings); 15 | assert.ok(federation); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /scripts/bitcoin-playnet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoind \ 3 | -regtest \ 4 | -server \ 5 | -txindex \ 6 | -datadir=./stores/bitcoin-playnet \ 7 | -fallbackfee=0.00001 \ 8 | -port=20445 \ 9 | -rpcport=20444 \ 10 | -connect=65.21.231.166:20445 \ 11 | -zmqpubrawblock=tcp://127.0.0.1:29500 \ 12 | -zmqpubrawtx=tcp://127.0.0.1:29500 \ 13 | -zmqpubhashtx=tcp://127.0.0.1:29500 \ 14 | -zmqpubhashblock=tcp://127.0.0.1:29500 \ 15 | -rpcbind=127.0.0.1 \ 16 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 17 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' 18 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpack = require('webpack'); 4 | 5 | module.exports = { 6 | entry: './index.js', 7 | // devtool: 'source-map', 8 | mode: 'development', 9 | target: 'web', 10 | output: { 11 | library: 'Fabric' 12 | }, 13 | plugins: [ 14 | new webpack.ProvidePlugin({ 15 | Peer: ['peerjs', 'default'] 16 | }), 17 | new webpack.DefinePlugin({ 18 | 'process.env': { 19 | NODE_ENV: JSON.stringify('production'), 20 | APP_ENV: JSON.stringify('browser') 21 | } 22 | }) 23 | ] 24 | }; 25 | -------------------------------------------------------------------------------- /scripts/keyloader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Wallet = require('../types/wallet'); 4 | const SEED = process.env.FABRIC_SEED; 5 | 6 | async function main () { 7 | const wallet = new Wallet(); 8 | const seed = await wallet._importSeed(SEED); 9 | const keypair = await wallet.generateCleanKeyPair(); 10 | console.warn('[FABRIC:KEYLOADER]', 'Key imported:', keypair); 11 | console.warn('[FABRIC:KEYLOADER]', 'SEED:', seed); 12 | process.exit(); 13 | } 14 | 15 | main().catch((E) => { 16 | console.error('[FABRIC:KEYLOADER]', 'Key loader threw Exception:', E); 17 | }); 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strictNullChecks": true, 4 | "moduleResolution": "node", 5 | "noUnusedParameters": true, 6 | "noUnusedLocals": true, 7 | "allowSyntheticDefaultImports": true, 8 | "target": "es5", 9 | "module": "ES2015", 10 | "declaration": true, 11 | "outDir": "./assets/types", 12 | "noImplicitAny": true, 13 | "importHelpers": true 14 | }, 15 | "include": [ 16 | "types/**/*", 17 | "index.d.ts", "contracts/deposit.js", // declaration file path 18 | ], 19 | "compileOnSave": false 20 | } 21 | -------------------------------------------------------------------------------- /types/bond.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Actor = require('@fabric/core/types/actor'); 4 | 5 | class Bond extends Actor { 6 | constructor (settings = {}) { 7 | super(settings); 8 | 9 | this.settings = Object.assign({ 10 | amount: null, 11 | expiry: null, 12 | issuer: null 13 | }, this.settings, settings); 14 | 15 | return this; 16 | } 17 | 18 | _getExpiry (type, time) { 19 | return { 20 | type, time, 21 | content: Buffer.alloc(4) // TODO: Bitcoin encoded values? 22 | }; 23 | }; 24 | } 25 | 26 | module.exports = Bond; 27 | -------------------------------------------------------------------------------- /schemata/SpendMessage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://hub.fabric.pub/schemata/SpendMessage.json", 4 | "title": "SpendMessage", 5 | "description": "Instance of a spend.", 6 | "type": "object", 7 | "properties": { 8 | "amount": { 9 | "description": "Amount (in BTC) to spend.", 10 | "type": "string" 11 | }, 12 | "destination": { 13 | "description": "Destination for funds.", 14 | "type": "string" 15 | } 16 | }, 17 | "required": [ 18 | "amount", 19 | "destination" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by node2nix 1.11.0. Do not edit! 2 | 3 | {pkgs ? import { 4 | inherit system; 5 | }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-16_x"}: 6 | 7 | let 8 | nodeEnv = import ./.nix/node-env.nix { 9 | inherit (pkgs) stdenv lib python2 runCommand writeTextFile writeShellScript; 10 | inherit pkgs nodejs; 11 | libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; 12 | }; 13 | in 14 | import ./.nix/node-packages.nix { 15 | inherit (pkgs) fetchurl nix-gitignore stdenv lib fetchgit; 16 | inherit nodeEnv; 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/web.js: -------------------------------------------------------------------------------- 1 | global.LOCAL_SERVER_CONFIG = { 2 | host: 'localhost', 3 | port: 9999, 4 | secure: false 5 | }; 6 | 7 | const http = require('http'); 8 | 9 | class Server{ 10 | constructor(){ 11 | this.server = http.createServer((req, res) => { 12 | res.setHeader('Content-Type', 'application/json'); 13 | res.end(JSON.stringify({status:200})); 14 | }); 15 | } 16 | 17 | async start(){ 18 | return this.server.listen(LOCAL_SERVER_CONFIG.port); 19 | } 20 | 21 | async stop(){ 22 | return this.server.close(); 23 | } 24 | } 25 | 26 | module.exports = {Server} 27 | -------------------------------------------------------------------------------- /tests/fabric.worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('../'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/worker', function () { 7 | describe('Worker', function () { 8 | xit('is available from @fabric/core', function () { 9 | assert.equal(Fabric.Worker instanceof Function, true); 10 | }); 11 | 12 | xit('can handle a task', async function () { 13 | let worker = new Fabric.Worker(); 14 | let result = await worker.compute(1); 15 | console.log('worker:', worker); 16 | console.log('result:', result); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/fabric.bech32.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Bech32 = require('../types/bech32'); 4 | const assert = require('assert'); 5 | 6 | const message = require('../assets/message'); 7 | const playnet = require('../settings/playnet'); 8 | 9 | describe('@fabric/core/types/bech32', function () { 10 | describe('Bech32', function () { 11 | it('is available from @fabric/core', function () { 12 | assert.equal(Bech32 instanceof Function, true); 13 | }); 14 | 15 | it('can create a new ECDSA bech32', function () { 16 | const bech32 = new Bech32(); 17 | assert.ok(bech32); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /contracts/chat.dot: -------------------------------------------------------------------------------- 1 | digraph Chat { 2 | "input" -> { 3 | "main" 4 | } -> "_generateOutput" -> "output" 5 | 6 | subgraph cluster_main { 7 | "main" 8 | "main" -> "_routeInput" -> { 9 | "_syncPeerList" 10 | "_syncMessageList" 11 | "_handleFormSubmit" 12 | "_handlePeerMessage" 13 | } -> "_generateOutput" 14 | 15 | subgraph cluster_methods { 16 | "_routeInput" 17 | "_syncPeerList" 18 | "_syncMessageList" 19 | "_handleFormSubmit" 20 | "_handlePeerMessage" 21 | } 22 | 23 | subgraph cluster_ui { 24 | "_generateOutput" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SERVICES.md: -------------------------------------------------------------------------------- 1 | # Fabric Services 2 | `@fabric/core` offers numerous Service implementations to provide basic 3 | Oracle functionality to the network. Requests made to Oracles can require 4 | BTC payments, allowing consumers to pay their providers for their services. 5 | 6 | ## Core Services 7 | - `@fabric/core/services/bitcoin` 8 | - `@fabric/core/services/lightning` 9 | 10 | ## External Services 11 | - `@fabric/github` 12 | - `@fabric/matrix` 13 | - `@fabric/twitter` 14 | 15 | ## Quick Start 16 | ``` 17 | const Bitcoin = require('@fabric/core/services/bitcoin'); 18 | const bitcoin = new Bitcoin(); 19 | 20 | bitcoin.start(); 21 | ``` 22 | -------------------------------------------------------------------------------- /settings/deprecations.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const FabricScribe = require('../types/scribe'); 4 | const FabricHTTPServer = require('../types/server'); 5 | const FabricStash = require('../types/stash'); 6 | 7 | /** 8 | * Deprecated 2021-10-16. 9 | * @deprecated 10 | */ 11 | class HTTPServer extends FabricHTTPServer {} 12 | 13 | /** 14 | * Deprecated 2021-11-06. 15 | * @deprecated 16 | */ 17 | class Scribe extends FabricScribe {} 18 | 19 | /** 20 | * Deprecated 2021-11-06. 21 | * @deprecated 22 | */ 23 | class Stash extends FabricStash {} 24 | 25 | module.exports = { 26 | HTTPServer, 27 | Scribe, 28 | Stash 29 | }; 30 | -------------------------------------------------------------------------------- /examples/chain.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Fabric Dependencies 4 | const Chain = require('../types/chain'); 5 | const chain = new Chain(); 6 | 7 | async function main () { 8 | await chain.storage.open(); 9 | 10 | chain.on('block', function (block) { 11 | console.log('[CHAIN]', 'new block:', block); 12 | console.log('[CHAIN]', 'chain:', chain); 13 | }); 14 | 15 | chain.append({ test: 'foo' }); 16 | chain.append({ test: 'bar' }); 17 | 18 | await chain.storage.close(); 19 | 20 | return this; 21 | } 22 | 23 | main().catch((exception) => { 24 | console.error('[EXAMPLES:CHAIN]', 'Main Process Exception:', exception); 25 | }); 26 | -------------------------------------------------------------------------------- /BUILD.md: -------------------------------------------------------------------------------- 1 | # Building Fabric From Source 2 | Documentation targeting Ubuntu. 3 | 4 | ## Major Services 5 | ### Bitcoin 6 | ``` 7 | sudo apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev 8 | git clone git@github.com:bitcoin/bitcoin.git 9 | cd bitcoin 10 | git checkout v0.21.1 11 | ./autogen.sh 12 | ./configure 13 | make 14 | sudo make install 15 | ``` 16 | 17 | ### Lightning 18 | ``` 19 | git clone git@github.com:ElementsProject/lightning.git 20 | cd lightning 21 | git checkout master 22 | ./autogen.sh 23 | ./configure 24 | make 25 | sudo make install 26 | ``` 27 | -------------------------------------------------------------------------------- /assets/app.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | meta(charset="UTF-8") 5 | title Fabric Oracle Sample App 6 | 7 | each script in scripts 8 | script(src="#{script.link}", integrity="#{script.integrity}") 9 | 10 | link(rel="import", href="https://polygit.org/components/polymer/polymer-element.html") 11 | link(rel="import", href="https://polygit.org/components/polymer/lib/elements/dom-repeat.html") 12 | 13 | each component in components 14 | link(rel="import", href="#{component.link}") 15 | 16 | link(rel="stylesheet", type="text/css", href="/assets/semantic.css") 17 | 18 | body 19 | fabric-application 20 | -------------------------------------------------------------------------------- /settings/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fabric/core", 3 | "description": "Application Resource Contract for the Fabric Execution Environment.", 4 | "language": "english", 5 | "network": "regtest", 6 | "interface": "0.0.0.0", 7 | "port": "7777", 8 | "resources": { 9 | "Event": { 10 | "name": "Event", 11 | "@comment": "// TODO: remove routes, add by default", 12 | "routes": { 13 | "list": "/events", 14 | "view": "/events/:id" 15 | } 16 | } 17 | }, 18 | "stack": [], 19 | "state": { 20 | "status": "PAUSED", 21 | "states": {}, 22 | "events": [] 23 | }, 24 | "history": [] 25 | } 26 | -------------------------------------------------------------------------------- /examples/message.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | // Dependencies 5 | const Message = require('../types/message'); 6 | 7 | // Main Process 8 | async function main () { 9 | // Create Message instance 10 | const message = Message.fromVector(['GenericMessage', '"Hello, world!"']); 11 | 12 | // Return generic Object 13 | return { 14 | message: message, 15 | raw: message.asRaw() 16 | }; 17 | } 18 | 19 | // Execution 20 | main().catch((exception) => { 21 | console.error('[EXAMPLES:MESSAGE]', 'Main Process Exception:', exception); 22 | }).then((output) => { 23 | console.log('[EXAMPLES:MESSAGE]', 'Main Process Output:', output); 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/miner.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const BLOCK_INTERVAL = process.env.BLOCK_INTERVAL || 60000; 4 | 5 | const Bitcoin = require('../services/bitcoin'); 6 | const settings = require('../settings/local'); 7 | 8 | async function main (input = {}) { 9 | const bitcoin = new Bitcoin(input); 10 | 11 | bitcoin.on('message', async function (msg) { 12 | console.log('[SCRIPTS:BITCOIN]', 'Received message:', msg); 13 | }); 14 | 15 | await bitcoin.start(); 16 | 17 | setInterval(() => { 18 | bitcoin.generateBlock(); 19 | }, BLOCK_INTERVAL); 20 | } 21 | 22 | main(settings).catch((E) => { 23 | console.error('[ALERT]', 'Service threw exception:', E); 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/schemata.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | async function main () { 6 | const schemata = {}; 7 | 8 | fs.readdirSync(__dirname + '/../schemata').forEach(function (file) { 9 | if (file.match(/\.json$/) !== null && file !== 'index.js') { 10 | const name = file 11 | .replace('.json', '') 12 | .replace('.js', ''); 13 | 14 | schemata[name] = null; 15 | // ... do stuff with the schemas? 16 | // or whatever else. 17 | // TODO: here for Eric's review. 18 | } 19 | }); 20 | 21 | return { schemata }; 22 | } 23 | 24 | main().then((output) => { 25 | console.log('Schemata:', output); 26 | }); 27 | -------------------------------------------------------------------------------- /types/transaction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Actor = require('./actor'); 4 | 5 | class Transaction extends Actor { 6 | constructor (settings = {}) { 7 | if (settings instanceof Transaction) return settings; 8 | 9 | super(settings); 10 | 11 | this.settings = Object.assign({ 12 | type: 'Transaction' 13 | }, settings); 14 | 15 | this._state = { 16 | settings: this.settings, 17 | content: Object.assign({ 18 | type: this.settings.type, 19 | }, settings) 20 | }; 21 | 22 | Object.defineProperty(this, 'history', { enumerable: false }); 23 | 24 | return this; 25 | } 26 | } 27 | 28 | module.exports = Transaction; 29 | -------------------------------------------------------------------------------- /types/value.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const MAX = Math.pow(2, 64); 4 | const BN = require('bn.js'); 5 | 6 | /** 7 | * {@link Number}-like type. 8 | */ 9 | class Value { 10 | /** 11 | * Use the {@link Value} type to interact with {@link Number}-like objects. 12 | * @param {Mixed} data Input value. 13 | */ 14 | constructor (data = {}) { 15 | this._state = { 16 | input: data, 17 | output: null 18 | }; 19 | } 20 | 21 | /** 22 | * Compute the numeric representation of this input. 23 | * @param {String} input Input string to seek for value. 24 | */ 25 | value (input) { 26 | return new BN(input); 27 | } 28 | } 29 | 30 | module.exports = Value; 31 | -------------------------------------------------------------------------------- /contracts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Fabric Types 4 | const Chain = require('../types/chain'); 5 | const Entity = require('../types/entity'); 6 | 7 | // Settings 8 | const data = require('../settings/test'); 9 | 10 | // Program Definition 11 | async function OP_TEST () { 12 | const chain = new Chain(data); 13 | await chain.start(); 14 | 15 | const bank = new Entity({ 16 | value: chain.subsidy 17 | }); 18 | 19 | await chain.append({ 20 | '@id': 'stub', 21 | '@data': { 22 | parent: chain.id, 23 | transactions: [ 24 | bank.id 25 | ] 26 | } 27 | }); 28 | 29 | return chain.id; 30 | } 31 | 32 | // Module 33 | module.exports = OP_TEST; 34 | -------------------------------------------------------------------------------- /tests/fabric.witness.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Witness = require('../types/witness'); 5 | 6 | const sample = { 7 | data: 'Hello, world!' 8 | }; 9 | 10 | describe('@fabric/core/types/witness', function () { 11 | describe('Witness', function () { 12 | it('is available from @fabric/core', function () { 13 | assert.equal(Witness instanceof Function, true); 14 | }); 15 | 16 | it('can instantiate from sample data', function (done) { 17 | async function test () { 18 | const witness = new Witness(sample); 19 | assert.ok(witness); 20 | done(); 21 | } 22 | 23 | test(); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /types/program.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Circuit = require('./circuit'); 4 | const Script = require('./script'); 5 | 6 | class Program extends Circuit { 7 | constructor (settings = {}) { 8 | super(settings); 9 | 10 | this.settings = Object.assign({ 11 | instructions: [] 12 | }, settings); 13 | 14 | this.circuit = new Circuit(); 15 | this.script = new Script(); 16 | 17 | this.state = {}; 18 | 19 | return this; 20 | } 21 | 22 | step () { 23 | console.log('[FABRIC:PROGRAM]', 'Executing step...'); 24 | } 25 | 26 | async start () { 27 | console.log('[FABRIC:PROGRAM]', 'Starting execution...'); 28 | } 29 | } 30 | 31 | module.exports = Program; 32 | -------------------------------------------------------------------------------- /examples/lightning.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Lightning = require('@fabric/core/services/lightning'); 4 | 5 | async function main () { 6 | const lightning = new Lightning({ 7 | mode: 'socket', 8 | path: './stores/lightning-playnet/regtest/lightning-rpc' 9 | }); 10 | 11 | await lightning.start(); 12 | 13 | const funds = await lightning._makeRPCRequest('listfunds'); 14 | 15 | return { 16 | id: lightning.id, 17 | funds: funds 18 | }; 19 | } 20 | 21 | main().catch((exception) => { 22 | console.error('[EXAMPLES:LIGHTNING]', 'Main Process Exception:', exception); 23 | }).then((output) => { 24 | console.log('[EXAMPLES:LIGHTNING]', 'Main Process Output:', output); 25 | }); 26 | -------------------------------------------------------------------------------- /examples/cluster/README.md: -------------------------------------------------------------------------------- 1 | # Cluster of Peers 2 | This directory contains scripts which configure a group networked peers, all communicating with one another using Fabric's P2P messaging components. 3 | 4 | ## Quick Start 5 | 6 | 0. Let your working directory be the Fabric repository. 7 | 1. Run `node examples/cluster/node-a.js` 8 | 2. Run `node examples/cluster/node-b.js` 9 | 3. Run `node examples/cluster/node-c.js` 10 | 4. Run `node examples/cluster/node-d.js` 11 | 5. Run `node examples/cluster/node-e.js` 12 | 13 | 14 | ## Network Topology 15 | ```dot 16 | digraph Cluster { 17 | "A" -> "B" [dir="both"] 18 | "B" -> "C" [dir="both"] 19 | "C" -> { 20 | "D" 21 | "E" 22 | } [dir="both"] 23 | } 24 | ``` -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 |

Fabric Browser Demo

13 |

Welcome to the Fabric browser demo.

14 | 15 |

To get started, select an application to boot.

16 | 17 |
    18 |
  • soundtrack, the collaborative music jukebox
  • 19 |
20 | 21 |

Fabric's playnet Sidechain

22 | 23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CONTRACTS.md: -------------------------------------------------------------------------------- 1 | # Fabric Contracts 2 | Contracts in Fabric are simple agreements between two or more peers. 3 | 4 | ## Contract Elements 5 | Fabric Contracts consist of several key components. 6 | 7 | - Initial Contract State 8 | - Contract Messages 9 | - Contract Script (Taproot Program) 10 | 11 | ## Using `@fabric/core/types/contract` 12 | The `Contract` type can be imported from `@fabric/core` using the following JavaScript: 13 | ```js 14 | const Contract = require('@fabric/core/types/contract`); 15 | ``` 16 | 17 | To deploy the contract, fund the deposit address generated by: 18 | ```js 19 | const Contract = require('@fabric/core/types/contract`); 20 | const contract = new Contract(); 21 | 22 | contract.deploy(); 23 | ``` 24 | -------------------------------------------------------------------------------- /contracts/node.js: -------------------------------------------------------------------------------- 1 | // # Fabric Peer Contract 2 | // Defines the behavior of a standard Fabric node. 3 | // 4 | // ## Quick Start 5 | // Install Fabric using `npm i -g @fabric/core` then execute `fabric start` to 6 | // run a local node. See `fabric --help` for additional options. 7 | 'use strict'; 8 | 9 | // Fabric Types 10 | const Node = require('../types/node'); 11 | 12 | // Program Definition 13 | async function OP_START (input = {}) { 14 | const node = new Node({ 15 | // TODO: configure with input? 16 | settings: (this && this.environment) ? this.environment.settings : { 17 | name: 'LOCALNODE' 18 | } 19 | }); 20 | 21 | return node.start(); 22 | } 23 | 24 | // Module 25 | module.exports = OP_START; 26 | -------------------------------------------------------------------------------- /examples/blockchain.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const MAX_BLOCK_COUNT = 9; 4 | 5 | const Block = require('../types/block'); 6 | const Chain = require('../types/chain'); 7 | 8 | const genesis = require('../assets/genesis'); 9 | 10 | async function main () { 11 | const chain = new Chain(); 12 | const origin = new Block(genesis); 13 | 14 | await chain.append(origin); 15 | 16 | for (let i = 0; i < MAX_BLOCK_COUNT; i++) { 17 | // Mine a block 18 | await chain.generateBlock(); 19 | } 20 | 21 | return chain.toString(); 22 | } 23 | 24 | main().catch((exception) => { 25 | console.error('[EXAMPLES:BLOCKCHAIN]', exception); 26 | }).then((output) => { 27 | console.log('[EXAMPLES:BLOCKCHAIN]', 'Output:', output); 28 | }); 29 | -------------------------------------------------------------------------------- /tests/fabric.entity.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('../'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/entity', function () { 7 | describe('Entity', function () { 8 | it('is available from @fabric/core', function () { 9 | assert.equal(Fabric.Entity instanceof Function, true); 10 | }); 11 | 12 | it('can generate a known string', function () { 13 | let entity = new Fabric.Entity({ foo: 'bar' }); 14 | assert.equal(entity.toString(), '{"foo":"bar"}'); 15 | }); 16 | 17 | it('can generate a known buffer', function () { 18 | let entity = new Fabric.Entity({ foo: 'bar' }); 19 | assert.equal(entity.toBuffer(), '{"foo":"bar"}'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /types/token.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const merge = require('lodash.merge'); 4 | const Actor = require('./actor'); 5 | const Label = require('./label'); 6 | 7 | class Token { 8 | constructor (settings = {}) { 9 | // Settings 10 | this.settings = merge({ 11 | name: 'AUTH_GROUP_GENERIC' 12 | }, settings); 13 | 14 | // Internal Properties 15 | this.actor = new Actor(this.settings); 16 | this.label = new Label(this.settings.name); 17 | 18 | // Chainable 19 | return this; 20 | } 21 | 22 | get id () { 23 | return this.actor.id; 24 | } 25 | 26 | get label () { 27 | return this.label._id; 28 | } 29 | 30 | toString () { 31 | return this.label; 32 | } 33 | } 34 | 35 | module.exports = Token; 36 | -------------------------------------------------------------------------------- /types/secret.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const crypto = require('crypto'); 4 | const EncryptedPromise = require('./promise'); 5 | 6 | class Secret extends EncryptedPromise { 7 | constructor (settings = {}) { 8 | super(settings); 9 | 10 | // assign internal secret 11 | this._secret = (typeof settings === 'string') ? settings : JSON.stringify(settings); 12 | 13 | // TODO: check and document upstream pattern 14 | this.load(); 15 | } 16 | 17 | get hash () { 18 | return crypto.createHash('sha256').update(this.data.content).digest('hex'); 19 | } 20 | 21 | get data () { 22 | return { 23 | hash: this._state.blob, 24 | content: this._state.blob.toString() 25 | } 26 | } 27 | } 28 | 29 | module.exports = Secret; 30 | -------------------------------------------------------------------------------- /tests/fabric.vector.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Vector = require('../types/vector'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/vector', function () { 7 | describe('Vector', function () { 8 | it('is a function', function () { 9 | assert.strictEqual(Vector instanceof Function, true); 10 | }); 11 | 12 | it('can restore from garbage', async function () { 13 | let vector = Vector.fromObjectString('{ "0": { "type": "Buffer", "data": [0, 0, 0, 0] } }'); 14 | assert.strictEqual(vector instanceof Array, true); 15 | assert.strictEqual(vector[0] instanceof Buffer, true); 16 | assert.strictEqual(vector[0].toString('hex'), '00000000'); 17 | assert.ok(vector); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/schemata.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Test Dependency 4 | const assert = require('assert'); 5 | 6 | // Schema-specific Dependencies 7 | const validator = require('is-my-json-valid'); 8 | const Actor = require('../types/actor'); 9 | 10 | // Schema Validation 11 | const registry = require('../schemata'); 12 | const validate = validator(registry.definitions.Actor); 13 | 14 | describe('JSON Schema Compliance', function () { 15 | describe('@fabric/core/types/actor', function () { 16 | it('produces valid JSON', function () { 17 | const actor = new Actor({ name: 'Satoshi Nakamoto' }); 18 | const valid = validate(actor); 19 | 20 | assert.ok(valid); 21 | assert.ok(actor); 22 | assert.ok(actor.id); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /types/path.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * A {@link Path} is a {@link Fabric}-native link to a {@link Document} 5 | * within the network. 6 | */ 7 | class Path extends String { 8 | /** 9 | * Create a new {@link Path}. 10 | * @param {String|Object} input Named path. 11 | */ 12 | constructor (input = {}) { 13 | super(input); 14 | 15 | if (typeof input === 'string') input = { input }; 16 | 17 | this.settings = Object.assign({ 18 | input: '/' 19 | }, settings); 20 | 21 | return this; 22 | } 23 | 24 | /** 25 | * @returns {Boolean} Whether or not the Path is valid. 26 | */ 27 | isValid () { 28 | return ( 29 | this.id.length === 32 30 | ) ? true : false; 31 | } 32 | } 33 | 34 | module.exports = Path; -------------------------------------------------------------------------------- /scripts/benchmark.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const iterations = 10000; 4 | const priors = { 5 | '100': 194, 6 | '1000': 3690, 7 | '10000': 378840 8 | }; 9 | 10 | const Collection = require('../types/collection'); 11 | const Machine = require('../types/machine'); 12 | 13 | async function benchmark () { 14 | let now = Date.now(); 15 | let collection = new Collection(); 16 | let machine = new Machine(); 17 | 18 | for (let i = 0; i < iterations; i++) { 19 | let item = { name: machine.sip() }; 20 | let instance = await collection.create(item); 21 | } 22 | 23 | let finish = Date.now(); 24 | let duration = finish - now; 25 | 26 | console.log('[BENCHMARK]', `Benchmark ended, ${iterations} run in ${duration} milliseconds.`); 27 | } 28 | 29 | benchmark(); 30 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (() => { 3 | const source = document.getElementsByClassName('prettyprint source linenums'); 4 | let i = 0; 5 | let lineNumber = 0; 6 | let lineId; 7 | let lines; 8 | let totalLines; 9 | let anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = `line${lineNumber}`; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/your-first-blockchain.md: -------------------------------------------------------------------------------- 1 | # Building Your First Blockchain 2 | In this example, we'll build a blockchain with Fabric. 3 | 4 | ## Quick Start 5 | Here's the complete code for launching a local chain, appending some data, and 6 | logging these events as they are received. 7 | 8 | ```js 9 | 'use strict'; 10 | 11 | const Chain = require('fabric').Chain; 12 | const chain = new Chain(); 13 | 14 | async function main () { 15 | await chain.storage.open(); 16 | 17 | chain.on('block', function (block) { 18 | console.log('[CHAIN]', 'new block:', block); 19 | }); 20 | 21 | chain.append({ input: 'foo' }); 22 | chain.append({ input: 'bar' }); 23 | 24 | await chain.storage.close(); 25 | } 26 | 27 | main(); 28 | ``` 29 | 30 | In practice, you'll want to add some validation function for the chain's `Block` 31 | definition. 32 | -------------------------------------------------------------------------------- /scripts/bitcoin-get-miner-address.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bitcoin-cli \ 3 | -regtest \ 4 | -rpcport=20444 \ 5 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 6 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 7 | createwallet miner 8 | 9 | bitcoin-cli \ 10 | -regtest \ 11 | -rpcport=20444 \ 12 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 13 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 14 | loadwallet miner 15 | 16 | bitcoin-cli \ 17 | -regtest \ 18 | -rpcport=20444 \ 19 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 20 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 21 | getnewaddress "mining" 22 | 23 | bitcoin-cli \ 24 | -regtest \ 25 | -rpcport=20444 \ 26 | -rpcuser='ahp7iuGhae8mooBahFaYieyaixei6too' \ 27 | -rpcpassword='naiRe9wo5vieFayohje5aegheenoh4ee' \ 28 | getaddressesbylabel "mining" 29 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Settings 4 | const settings = require('../settings/local'); 5 | 6 | // Types 7 | const Peer = require('../types/peer'); 8 | const Site = require('@fabric/http/types/site'); 9 | const Compiler = require('@fabric/http/types/compiler'); 10 | 11 | // Program Body 12 | async function main (input = {}) { 13 | const peer = new Peer(); 14 | const site = new Site(input); 15 | const compiler = new Compiler({ 16 | document: site 17 | }); 18 | 19 | await compiler.compileTo('assets/index.html'); 20 | 21 | return { 22 | site: site.id, 23 | peer: peer 24 | }; 25 | } 26 | 27 | // Run Program 28 | main(settings).catch((exception) => { 29 | console.error('[BUILD:SITE]', '[EXCEPTION]', exception); 30 | }).then((output) => { 31 | console.log('[BUILD:SITE]', '[OUTPUT]', output); 32 | }); 33 | -------------------------------------------------------------------------------- /services/local.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Service = require('../types/service'); 4 | 5 | class Local extends Service { 6 | constructor (config) { 7 | super(config); 8 | this.config = Object.assign({ 9 | path: './stores/local' 10 | }, config); 11 | return this; 12 | } 13 | 14 | handler (message) { 15 | this.log('[LOCAL:HANDLER]', 'handling message:', message); 16 | let data = Object.assign({ 17 | actor: message.user, 18 | target: message.channel, 19 | object: message.text, 20 | origin: { 21 | type: 'Link', 22 | name: 'Internal' 23 | } 24 | }, message); 25 | this.emit('message', data); 26 | } 27 | 28 | async start () { 29 | this.log('[LOCAL:START]', 'starting...'); 30 | return super.start(); 31 | } 32 | } 33 | 34 | module.exports = Local; 35 | -------------------------------------------------------------------------------- /contracts/mount.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Fabric Types 4 | const Filesystem = require('../types/filesystem'); 5 | 6 | // Program Definition 7 | async function OP_MOUNT (command) { 8 | const filesystem = new Filesystem({ 9 | path: command.args[0] || '.fabric' 10 | }); 11 | 12 | filesystem.on('activity', activity => { 13 | console.log('activity:', activity); 14 | }); 15 | 16 | filesystem.on('log', log => { 17 | console.log('log:', log); 18 | }); 19 | 20 | filesystem.on('message', message => { 21 | console.log('message:', message); 22 | }); 23 | 24 | filesystem.on('error', error => { 25 | console.error('error:', error); 26 | }); 27 | 28 | await filesystem.start(); 29 | return JSON.stringify({ 30 | id: filesystem.id, 31 | type: 'FabricFileSystem' 32 | }); 33 | } 34 | 35 | // Module 36 | module.exports = OP_MOUNT; 37 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /examples/cli.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const CLI = require('../types/cli'); 4 | const config = { 5 | path: `./stores/${process.env['NAME'] || 'cli'}`, 6 | persistent: true, 7 | oracle: { 8 | port: process.env['PORT'] || 3007 9 | } 10 | }; 11 | 12 | async function main () { 13 | const cli = new CLI(config); 14 | 15 | try { 16 | await cli.start(); 17 | } catch (E) { 18 | cli.error(`λ`, 'main()', E); 19 | } 20 | 21 | cli.on('changes', async function (msg) { 22 | cli.log('[MAIN:CLI]', 'cli event changes:', msg); 23 | }); 24 | 25 | cli.on('state', function (msg) { 26 | cli.log('[MAIN:CLI]', 'state:', msg); 27 | }); 28 | 29 | cli.on('state/tip', function (msg) { 30 | cli.log('[MAIN:CLI]', 'state/tip:', msg); 31 | }); 32 | 33 | cli.on('error', function (E) { 34 | console.error('EXCEPTION:', E); 35 | }); 36 | } 37 | 38 | main(); 39 | -------------------------------------------------------------------------------- /examples/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // # Importing the Environment type 4 | const Environment = require('@fabric/core/types/environment'); 5 | 6 | // Define 7 | async function main () { 8 | // Create an instance 9 | const environment = new Environment(); 10 | 11 | // Create an object containing our output 12 | return { 13 | // As with all Fabric types, the `id` property is deterministic, being 14 | // derived from the `settings` object as provided to the constructor. 15 | id: environment.id, 16 | // If the environment provides a wallet, it will be listed here 17 | wallet: environment.wallet?.id 18 | }; 19 | } 20 | 21 | // Run the example 22 | main().catch((exception) => { 23 | console.error('[EXAMPLE:ENVIRONMENT]', '[EXCEPTION]', exception); 24 | }).then((output) => { 25 | console.log('[EXAMPLE:ENVIRONMENT]', '[OUTPUT]', output); 26 | }); 27 | -------------------------------------------------------------------------------- /types/component.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const lexer = require('jade-lexer'); 4 | const parse = require('jade-parser'); 5 | 6 | const Service = require('./service'); 7 | 8 | class Component extends Service { 9 | constructor (config) { 10 | this.config = Object.assign({ 11 | 'encoding': 'jade', 12 | 'input': 'fabric-component Hello, world!' 13 | }, config); 14 | 15 | this['@encoding'] = 'html'; 16 | 17 | this.tokens = lexer(this.config.input); 18 | this.ast = parse(this.tokens); 19 | 20 | return this; 21 | } 22 | 23 | toHTML (ast) { 24 | return ``; 25 | } 26 | 27 | render () { 28 | let result = null; 29 | 30 | switch (this['@encoding']) { 31 | default: 32 | result = this.toHTML(this.ast); 33 | break; 34 | } 35 | 36 | return result; 37 | } 38 | } 39 | 40 | module.exports = Component; 41 | -------------------------------------------------------------------------------- /tests/fabric.federation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const settings = require('../settings/test'); 5 | const Federation = require('../types/federation'); 6 | 7 | describe('@fabric/core/types/federation', function () { 8 | describe('Federation', function () { 9 | xit('is available from @fabric/core', function () { 10 | assert.equal(Federation instanceof Function, true); 11 | }); 12 | 13 | it('can smoothly create a new federation', function () { 14 | const federation = new Federation(); 15 | assert.ok(federation); 16 | assert.ok(federation.id); 17 | }); 18 | 19 | it('can start and stop', async function () { 20 | const federation = new Federation(); 21 | federation.start(); 22 | federation.stop(); 23 | assert.ok(federation); 24 | assert.ok(federation.id); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | pull_request: 4 | branches: 5 | - '**' 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | test: 11 | name: Run tests 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: 16 | - macos-latest 17 | - ubuntu-latest 18 | steps: 19 | - name: Checkout branch 20 | uses: actions/checkout@v3 21 | - name: Install Node.js on ${{ matrix.os }} 22 | uses: actions/setup-node@v2 23 | with: 24 | node-version-file: '.nvmrc' 25 | cache: 'npm' 26 | cache-dependency-path: package-lock.json 27 | - name: Install dependencies 28 | run: npm ci 29 | - name: Generate coverage report 30 | run: npm run report:coverage 31 | - name: Send coverage report 32 | uses: codecov/codecov-action@v3.1.1 33 | with: 34 | directory: ./reports/ 35 | -------------------------------------------------------------------------------- /examples/bitcoin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('debug-trace')({ always: true }); 4 | 5 | const Fabric = require('../'); 6 | const Bitcoin = require('../services/bitcoin'); 7 | const Wallet = require('../types/wallet'); 8 | 9 | async function main () { 10 | let fabric = new Fabric(); 11 | let bitcoin = new Bitcoin({ network: 'regtest' }); 12 | // let wallet = new Wallet(); 13 | 14 | bitcoin.on('message', function (msg) { 15 | console.log('[DEVELOP]', 'Bitcoin emitted message:', msg); 16 | }); 17 | 18 | // fabric.use(bitcoin); 19 | await bitcoin.start(); 20 | // await wallet.start(); 21 | 22 | // TODO: import these into core process logic 23 | // await wallet._scanChainForTransactions(bitcoin.blockchain); 24 | 25 | // console.log('fabric:', fabric); 26 | console.log('bitcoin state:', bitcoin.state); 27 | // console.log('wallet state:', wallet.state); 28 | } 29 | 30 | module.exports = main(); -------------------------------------------------------------------------------- /tests/fabric.swarm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // require('debug-trace')({ always: true }); 4 | 5 | const config = require('../settings/test'); 6 | const Swarm = require('../types/swarm'); 7 | 8 | // Testing 9 | const assert = require('assert'); 10 | 11 | describe('@fabric/core/types/swarm', function () { 12 | describe('Swarm', function () { 13 | it('should expose a constructor', function () { 14 | assert.equal(Swarm instanceof Function, true); 15 | }); 16 | 17 | it('can start and stop cleanly', async function () { 18 | const swarm = new Swarm(); 19 | await swarm.start(); 20 | await swarm.stop(); 21 | assert.ok(swarm); 22 | }); 23 | 24 | it('can start and stop with the test configuration', async function () { 25 | const swarm = new Swarm(config); 26 | await swarm.start(); 27 | await swarm.stop(); 28 | assert.ok(swarm); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installing Fabric 2 | ## Prerequisites 3 | - Node.js 16.17.1 4 | 5 | ## Quick Start 6 | You can install Fabric by running: 7 | ``` 8 | npm i -g FabricLabs/fabric#feature/cleanup 9 | ``` 10 | 11 | This will make the `fabric` binary available on your system, after which you should run: 12 | ``` 13 | fabric setup 14 | ``` 15 | 16 | Now, you'll have a newly-generated Fabric address and you can run: 17 | ``` 18 | fabric 19 | ``` 20 | 21 | ## Playnet 22 | By default, the Fabric CLI connects to `playnet` for an initial set of peers. You can add new peers manually by running `/connect
` where ` is the peer's public hostname and port. 23 | 24 | ## Notes 25 | If you don't have Node.js, or an incorrect version, we recommend [installing NVM][installing-nvm]. Once complete, you can install and set the default node version: 26 | ``` 27 | nvm install 16.17.1 28 | nvm alias default 16.17.1 # optional 29 | ``` 30 | 31 | [installing-nvm]: https://nvm.sh 32 | -------------------------------------------------------------------------------- /tests/fabric.tree.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Tree = require('../types/tree'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/tree', function () { 7 | describe('Tree', function () { 8 | it('is available from @fabric/core', function () { 9 | assert.strictEqual(Tree instanceof Function, true); 10 | }); 11 | 12 | it('can construct an empty tree', async function () { 13 | let tree = new Tree(); 14 | assert.ok(tree); 15 | assert.ok(tree._tree); 16 | assert.ok(tree.root); 17 | assert.strictEqual(tree.root.toString('hex'), ''); // TODO: wat? 18 | }); 19 | 20 | it('can construct a known tree', async function () { 21 | let tree = new Tree(['foo', 'bar']); 22 | assert.ok(tree); 23 | assert.ok(tree._tree); 24 | assert.strictEqual(tree.root.toString('hex'), '906b5aaf65ae98f8c98848de5e81ba865659f16fd53aefa4c78b34176f068079'); // TODO: wat? 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /schemata/activity.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://hub.fabric.pub/schemata/activity.schema.json", 4 | "title": "Activity", 5 | "description": "Activity in a Stream.", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The unique identifier for an activity.", 10 | "type": "string" 11 | }, 12 | "actor": { 13 | "description": "The activity's creator.", 14 | "type": "Actor|String" 15 | }, 16 | "created": { 17 | "description": "ISO 8601 creation time.", 18 | "type": "string" 19 | }, 20 | "object": { 21 | "description": "The unique identifier for an activity.", 22 | "type": "object" 23 | }, 24 | "target": { 25 | "description": "Path to write.", 26 | "type": "object" 27 | } 28 | }, 29 | "required": [ 30 | "id", 31 | "object", 32 | "target" 33 | ], 34 | "version": "0.1.0-RC1" 35 | } 36 | -------------------------------------------------------------------------------- /types/script.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Stack = require('./stack'); 4 | 5 | // addresses of known operators 6 | const known = { 7 | 'OP_0': '0x5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9', 8 | 'OP_1': '0x6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' 9 | }; 10 | 11 | class Script extends Stack { 12 | /** 13 | * Compose a {@link Script} for inclusion within a {@link Contract}. 14 | * @param {Mixed} config Configuration options for the script. 15 | * @return {Script} Instance of the {@link Script}, ready for use. 16 | */ 17 | constructor (config) { 18 | super(config); 19 | this.stack = new Stack(); 20 | this['@data'] = this.stack['@data']; 21 | return this; 22 | } 23 | 24 | compile () { 25 | return this.stack.map(x => { 26 | return known[x] || x; 27 | }); 28 | } 29 | 30 | render () { 31 | return this.stack.join(' '); 32 | } 33 | } 34 | 35 | module.exports = Script; 36 | -------------------------------------------------------------------------------- /tests/bitcoin/transaction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Transaction = require('../../types/bitcoin/transaction'); 5 | 6 | const settings = require('../../settings/test'); 7 | 8 | describe('@fabric/core/types/bitcoin/transaction', function () { 9 | it('is available from @fabric/core', function () { 10 | assert.equal(Transaction instanceof Function, true); 11 | }); 12 | 13 | it('creates an empty instance', function () { 14 | const tx = new Transaction(); 15 | assert.ok(tx); 16 | }); 17 | 18 | it('provides a hash', function () { 19 | const tx = new Transaction(); 20 | assert.ok(tx); 21 | assert.ok(tx.hash); 22 | }); 23 | 24 | it('provides a txid', function () { 25 | const tx = new Transaction(); 26 | assert.ok(tx); 27 | assert.ok(tx.txid); 28 | }); 29 | 30 | it('provides an id', function () { 31 | const tx = new Transaction(); 32 | assert.ok(tx); 33 | assert.ok(tx.id); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /settings/bitcoin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bitcoin", 3 | "symbol": "BTC", 4 | "genesis": { 5 | "version": "01000000", 6 | "parent": "0000000000000000000000000000000000000000000000000000000000000000", 7 | "root": "3BA3EDFD7A7B12B27AC72C3E67768F617FC81BC3888A51323A9FB8AA4B1E5E4A", 8 | "timestamp": "29AB5F49", 9 | "bits": "FFFF001D", 10 | "nonce": "1DAC2B7C", 11 | "transactions": [ 12 | { 13 | "version": "01000000", 14 | "index": "01", 15 | "spends": ["0000000000000000000000000000000000000000000000000000000000000000FFFFFFFF"] 16 | } 17 | ] 18 | }, 19 | "bootstrap": { 20 | "dns": [ 21 | "dnsseed.bitcoin.dashjr.org", 22 | "dnsseed.bluematt.me", 23 | "dnsseed.emzy.de", 24 | "seed.bitcoin.jonasschnelli.ch", 25 | "seed.bitcoin.sipa.be", 26 | "seed.bitcoin.sprovoost.nl", 27 | "seed.bitcoinstats.com", 28 | "seed.bitcoin.wiz.biz", 29 | "seed.btc.petertodd.org" 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /types/bech32.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bech32 = require('bech32-buffer'); 4 | const { 5 | bech32m 6 | } = require('bech32'); 7 | 8 | class Bech32 { 9 | constructor (input = {}) { 10 | this.settings = Object.assign({ 11 | hrp: 'bc', 12 | separator: '1', 13 | content: '' 14 | }, input); 15 | 16 | return this; 17 | } 18 | 19 | get content () { 20 | return this.settings.content; 21 | } 22 | 23 | get hrp () { 24 | return this.settings.hrp; 25 | } 26 | 27 | get words () { 28 | const buffer = (this.content instanceof Buffer) ? this.content : Buffer.from(this.content, 'hex'); 29 | return bech32m.toWords(buffer); 30 | } 31 | 32 | static decode (input = '') { 33 | const decoded = bech32.decode(input); 34 | return { 35 | prefix: decoded.prefix, 36 | content: decoded.data 37 | }; 38 | } 39 | 40 | toString () { 41 | return bech32m.encode(this.hrp, this.words); 42 | } 43 | } 44 | 45 | module.exports = Bech32; 46 | -------------------------------------------------------------------------------- /types/bitcoin/block.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Actor = require('../actor'); 4 | // const Consensus = require('../consensus'); 5 | const Transaction = require('./transaction'); 6 | 7 | class BitcoinBlock extends Actor { 8 | constructor (settings = {}) { 9 | super(settings); 10 | 11 | this.settings = Object.assign({ 12 | provider: 'bcoin', 13 | network: 'regtest' 14 | }, settings); 15 | 16 | // this.consensus = new Consensus(this.settings); 17 | this._state = { 18 | content: {}, 19 | transactions: [] 20 | }; 21 | 22 | return this; 23 | } 24 | 25 | get data () { 26 | return this.settings; 27 | } 28 | 29 | toBitcoinBlock () { 30 | const Block = this.consensus.Block; 31 | const block = new Block({ 32 | txs: this.state.transactions.map((x) => { 33 | return new Transaction({ 34 | hash: x 35 | }); 36 | }) 37 | }); 38 | return block; 39 | } 40 | } 41 | 42 | module.exports = BitcoinBlock; 43 | -------------------------------------------------------------------------------- /types/snapshot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const crypto = require('crypto'); 4 | 5 | /** 6 | * A type of message to be expected from a {@link Service}. 7 | */ 8 | class Snapshot { 9 | /** 10 | * Creates an instance of a {@link Snapshot}. 11 | * @param {Object} settings Map of settings to configure the {@link Snapshot} with. 12 | */ 13 | constructor (settings = {}) { 14 | this.settings = Object.assign({ 15 | '@type': 'Snapshot' 16 | }, settings); 17 | 18 | // Stores local state 19 | this._state = null; 20 | } 21 | 22 | set state (state) { 23 | if (!state) throw new Error('State must be provided.'); 24 | this._state = state; 25 | } 26 | 27 | get state () { 28 | return Object.assign({}, this._state); 29 | } 30 | 31 | /** 32 | * Retrieves the `sha256` fingerprint for the {@link Snapshot} state. 33 | */ 34 | commit () { 35 | return crypto.createHash('sha256').update(JSON.stringify(this.state)).digest('hex'); 36 | } 37 | } 38 | 39 | module.exports = Snapshot; 40 | -------------------------------------------------------------------------------- /examples/witness.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('debug-trace')({ always: true }); 4 | 5 | const Witness = require('../types/witness'); 6 | const sample = 'Hello, world!'; 7 | const privkey = 'e6324f909a861b953e42438c2d4068dee59d576c32150309eaee07ceb21233a'; 8 | 9 | async function main () { 10 | let witness = new Witness({ 11 | data: sample, 12 | keypair: { 13 | private: privkey 14 | } 15 | }); 16 | 17 | console.log('Witness:', witness); 18 | console.log('Signature:', witness.signature); 19 | console.log('Bitcoin DER:', witness.toCompactDER()); 20 | console.log('Bitcoin DER as hex:', witness.toCompactDER().toString('hex')); 21 | console.log('Witness pubkey:', witness.pubkey); 22 | 23 | let verifier = new Witness({ 24 | keypair: { public: witness.pubkey } 25 | }); 26 | 27 | console.log('Verifier:', verifier); 28 | console.log('Verifier keypair:', verifier.keypair); 29 | 30 | let verification = verifier.verify(sample, witness.signature); 31 | console.log('Verification:', verification); 32 | } 33 | 34 | main(); -------------------------------------------------------------------------------- /tests/fabric.identity.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Identity = require('../types/identity'); 4 | const assert = require('assert'); 5 | 6 | const SAMPLE = { 7 | seed: 'cricket grocery kingdom wool double wood happy predict worth pave build pepper bullet farm churn exhibit grit isolate short theory help vehicle denial slide' 8 | }; 9 | 10 | describe('@fabric/core/types/identity', function () { 11 | describe('Identity', function () { 12 | it('is available from @fabric/core', function () { 13 | assert.equal(Identity instanceof Function, true); 14 | }); 15 | 16 | it('can create a new ECDSA identity', function () { 17 | const identity = new Identity(); 18 | assert.ok(identity); 19 | }); 20 | 21 | it('provides the correct public key for a known seed phrase', function () { 22 | const identity = new Identity({ 23 | seed: SAMPLE.seed 24 | }); 25 | 26 | assert.ok(identity); 27 | assert.equal(identity.pubkey, '3b7a27a51582e9e9cc1d820dc9105bdbd12dfe96c471a1a5cf5cff7e8fab566'); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /tests/fabric.oracle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Oracle = require('../types/oracle'); 5 | 6 | const message = require('../assets/message'); 7 | 8 | describe('@fabric/core/types/oracle', function () { 9 | describe('Oracle', function () { 10 | it('is available from @fabric/core', function () { 11 | assert.equal(Oracle instanceof Function, true); 12 | }); 13 | 14 | it('can use _SET', async function () { 15 | let oracle = new Oracle(); 16 | 17 | await oracle.start(); 18 | await oracle._SET('sample', message['@data']); 19 | await oracle.stop(); 20 | 21 | assert.ok(oracle); 22 | }); 23 | 24 | xit('can store a string value', async function () { 25 | let oracle = new Oracle(); 26 | 27 | await oracle.start(); 28 | let set = await oracle._SET('sample', message['@data']); 29 | let get = await oracle._GET('sample'); 30 | await oracle.stop(); 31 | 32 | assert.ok(oracle); 33 | assert.equal(typeof get, 'string'); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /tests/fabric.scribe.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('../'); 4 | const assert = require('assert'); 5 | 6 | const Scribe = require('../types/scribe'); 7 | 8 | describe('@fabric/core/types/app', function () { 9 | describe('Scribe', function () { 10 | it('is available from @fabric/core', function () { 11 | assert.equal(Fabric.Scribe instanceof Function, true); 12 | }); 13 | 14 | it('should expose a constructor', function () { 15 | assert(Scribe instanceof Function); 16 | }); 17 | 18 | xit('should inherit to a stack', function () { 19 | let parent = new Scribe({ namespace: 'parent' }); 20 | let scribe = new Scribe(); 21 | 22 | scribe.inherits(parent); 23 | 24 | console.log('scribe stack:', scribe.stack); 25 | assert.equal(scribe.stack[0], 'parent'); 26 | }); 27 | 28 | xit('should log some series of tags', function () { 29 | let scribe = new Scribe(); 30 | let result = scribe.log('debug', 'messaging', 'some data'); 31 | 32 | assert.ok(result); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/fabric.logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const assert = require('assert'); 5 | const Logger = require('../types/logger'); 6 | 7 | const path = './logs/test'; 8 | 9 | describe('@fabric/core/types/logger', function () { 10 | describe('Logger', function () { 11 | it('should handle strings', async function () { 12 | const start = (new Date()).toISOString(); 13 | const logger = new Logger({ path }); 14 | await logger.start(); 15 | await logger.log(`${start} [TEST] Hello, world!`); 16 | await logger.stop(); 17 | assert.ok(logger); 18 | assert.ok(fs.existsSync(logger.path)); 19 | }); 20 | 21 | it('should handle pure objects', async function () { 22 | const start = (new Date()).toISOString(); 23 | const logger = new Logger({ path }); 24 | await logger.start(); 25 | await logger.log({ 26 | content: `${start} [TEST] Hello, world!` 27 | }); 28 | await logger.stop(); 29 | assert.ok(logger); 30 | assert.ok(fs.existsSync(logger.path)); 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /tests/fabric.reader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Dependencies 4 | const assert = require('assert'); 5 | 6 | // Fabric Types 7 | const Reader = require('../types/reader'); 8 | const Message = require('../types/message'); 9 | 10 | describe('@fabric/core/types/reader', function () { 11 | describe('Reader', function () { 12 | it('is a constructor', function () { 13 | assert.strictEqual(Reader instanceof Function, true); 14 | }); 15 | 16 | it('can parse a well-formatted message', function (done) { 17 | const reader = new Reader(); 18 | const message = Message.fromVector(['Generic', 'Hello, world!']); 19 | const raw = message.toRaw(); 20 | 21 | reader.on('message', function (msg) { 22 | const message = Message.fromBuffer(msg); 23 | assert.strictEqual(message.body, 'Hello, world!'); 24 | done(); 25 | }); 26 | 27 | reader._addData(raw); 28 | 29 | assert.ok(reader); 30 | assert.strictEqual(message.toObject().headers.hash, '315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3'); 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /examples/fabric.js: -------------------------------------------------------------------------------- 1 | // # Getting Started with Fabric 2 | // Fabric provides an API for writing, compiling, and executing distributed 3 | // applications. In this example, we'll walk through a few of the basic 4 | // operations a typical application might utilize, staying as close to 5 | // production-quality code as we can. :) 6 | 7 | // Strict mode is used to enforce certain constraints on JavaScript, and is 8 | // generally recommended for use when building applications with Fabric. 9 | 'use strict'; 10 | 11 | // Since our example begins _within_ the Fabric repository, we're going to 12 | // call `require` against the local directory, but in a real-world 13 | // application you'll want to use `const Fabric = require('@fabric/core');` 14 | // to use the correct package (installed with `npm i @fabric/core` of 15 | // course!) 16 | const Fabric = require('../'); 17 | 18 | // We're going to contain our application withing a `main` function, defined 19 | // here using the `async` prefix. 20 | async function main() { 21 | let fabric = new Fabric(); 22 | console.log('[EXAMPLE]', 'Fabric:', fabric); 23 | } 24 | 25 | // Finally, let's run our program. 26 | main(); -------------------------------------------------------------------------------- /types/document.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Vector = require('./vector'); 4 | 5 | class Document extends Vector { 6 | constructor (doc) { 7 | super(doc); 8 | 9 | // only valid if this matches 10 | this.contract = { 11 | integrity: `sha256-${this.hash}` 12 | }; 13 | 14 | return this; 15 | } 16 | 17 | /** 18 | * Compiles an `input` {@link Vector}. 19 | * ENV provides the name of a parent type (e.g., "scaffold" or "0xDEADBEEF...") 20 | * UI provides the name of the desired component 21 | * @param {Vector} input [env, ui] 22 | * @return {Promise} Promise which resolves on compilation. 23 | */ 24 | async compile (input) { 25 | let vector = new Vector(input)._sign(); 26 | let contract = [ 27 | `extends ${input[0]}`, 28 | `block body`, 29 | ` ${input[1]}(state="${vector.id}") {{state}}` 30 | ].join('\n'); 31 | 32 | this.contract = contract; 33 | this['@id'] = vector.id; 34 | await this.commit(); 35 | 36 | return contract; 37 | } 38 | 39 | toString () { 40 | return ``; 41 | } 42 | } 43 | 44 | module.exports = Document; 45 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Eric Martindale 4 | Copyright (c) 2017 Fabric Labs 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Eric Martindale 4 | Copyright (c) 2017 Fabric Labs 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/fabric.signer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fixtures = require('../fixtures'); 4 | const config = require('../settings/test'); 5 | const Actor = require('../types/actor'); 6 | const Hash256 = require('../types/hash256'); 7 | const Message = require('../types/message'); 8 | const Signer = require('../types/signer'); 9 | 10 | // Testing 11 | const assert = require('assert'); 12 | 13 | describe('@fabric/core/types/signer', function () { 14 | describe('Signer', function () { 15 | it('should expose a constructor', function () { 16 | assert.equal(Signer instanceof Function, true); 17 | }); 18 | 19 | it('can start and stop cleanly', async function () { 20 | const signer = new Signer(); 21 | await signer.start(); 22 | assert.strictEqual(signer.status, 'STARTED'); 23 | await signer.stop(); 24 | assert.ok(signer); 25 | }); 26 | 27 | it('can start and stop with the test configuration', async function () { 28 | const signer = new Signer(config); 29 | await signer.start(); 30 | assert.strictEqual(signer.status, 'STARTED'); 31 | await signer.stop(); 32 | assert.ok(signer); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /fixtures.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Zero Entropy 4 | const TEST_SEED = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; 5 | const TEST_XPRV = 'xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF'; 6 | const TEST_XPUB = 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8'; 7 | 8 | // Strings 9 | const EMPTY_STRING = ''; 10 | const FABRIC_HELLO_WORLD = 'Hello, World!'; 11 | const HELLO_FABRIC = 'Hello, Fabric!'; 12 | const HELLO_WORLD = 'Hello World'; 13 | const GITHUB_ISSUE_PATH = 'FabricLabs/fabric/issues/1'; 14 | 15 | // Module 16 | module.exports = { 17 | EMPTY_STRING: EMPTY_STRING, 18 | FABRIC_HELLO_WORLD: FABRIC_HELLO_WORLD, 19 | FABRIC_SEED: TEST_SEED, 20 | FABRIC_XPRV: TEST_XPRV, 21 | FABRIC_XPUB: TEST_XPUB, 22 | FIXTURE_SEED: TEST_SEED, 23 | GITHUB_ISSUE_PATH: GITHUB_ISSUE_PATH, 24 | HELLO_FABRIC: HELLO_FABRIC, 25 | HELLO_WORLD: HELLO_WORLD, 26 | PLAYNET_SEED: TEST_SEED, 27 | TEST_SEED: TEST_SEED, 28 | seed: TEST_SEED, 29 | xprv: TEST_XPRV, 30 | identity: { 31 | xpub: TEST_XPUB 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /tests/fabric.state.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('../'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/state', function () { 7 | describe('State', function () { 8 | it('is available from @fabric/core', function () { 9 | assert.equal(Fabric.State instanceof Function, true); 10 | }); 11 | 12 | xit('provides an accurate "@id" attribute', function () { 13 | let state = new Fabric.State(message['@data']); 14 | 15 | assert.ok(state); 16 | assert.equal(state.id, message['@id']); 17 | }); 18 | 19 | xit('can serialize to a sane element', function () { 20 | let state = new Fabric.State(message['@data']); 21 | 22 | assert.ok(state); 23 | assert.equal(state.id, message['@id']); 24 | assert.equal(state.serialize(), JSON.stringify(message['@data'])); 25 | }); 26 | 27 | xit('can deserialize from a string', function () { 28 | let state = Fabric.State.fromString(JSON.stringify(message['@data'])); 29 | 30 | assert.ok(state); 31 | assert.equal(state.id, message['@id']); 32 | assert.equal(state.serialize(), JSON.stringify(message['@data'])); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | Welcome to Fabric! 3 | 4 | ## Overview 5 | * [🤔 Introduction][readme] 6 | * [👀 Quick Start][quickstart] 7 | * [🎯 Goals][goals] 8 | * [🔭 Roadmap][roadmap] 9 | * [看板 kanban][meta] 10 | 11 | ## Documentation 12 | * [🤯 Developer Introduction][developers] 13 | * [🖥️ API Documentation][api-docs] 14 | * [🖨️ API Reference Sheet][api-md] 15 | * [📜 Code Samples][api-examples] 16 | 17 | ## Guides 18 | * [⚙️ Settings][settings] 19 | * [🏦 Services Overview][services] 20 | * [💁 Contributing][contributing] 21 | * [✅ TODO List][todo] 22 | 23 | ## Archive 24 | * [📄 Whitepaper (latest)][whitepaper] 25 | * [📃 Whitepaper (2015)][whitepaper-2015] 26 | 27 | [api-md]: API.md 28 | [api-docs]: https://dev.fabric.pub/docs 29 | [api-examples]: https://dev.fabric.pub/examples 30 | 31 | [readme]: README.md 32 | [welcome]: WELCOME.md 33 | [quickstart]: QUICKSTART.md 34 | [whitepaper]: whitepaper.md 35 | [whitepaper-2015]: whitepaper-2015.md 36 | [developers]: DEVELOPERS.md 37 | [actors]: ACTORS.md 38 | [services]: SERVICES.md 39 | [settings]: SETTINGS.md 40 | [contributing]: CONTRIBUTING.md 41 | [goals]: GOALS.md 42 | [todo]: TODO.md 43 | [roadmap]: https://github.com/FabricLabs/fabric/projects/1 44 | [meta]: https://github.com/orgs/FabricLabs/projects/1 45 | -------------------------------------------------------------------------------- /types/bitcoin/transaction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const crypto = require('crypto'); 4 | 5 | const Actor = require('../actor'); 6 | const Signer = require('../signer'); 7 | const Transaction = require('../transaction'); 8 | // TODO: PSBTs 9 | 10 | class BitcoinTransaction extends Actor { 11 | constructor (settings = {}) { 12 | super(settings); 13 | 14 | this.settings = Object.assign({ 15 | raw: null 16 | }, settings); 17 | 18 | this.holder = new Signer(this.settings.signer); 19 | 20 | this.inputs = []; 21 | this.outputs = []; 22 | this.script = null; 23 | this.signature = null; 24 | 25 | this._state = { 26 | content: { 27 | raw: null 28 | }, 29 | status: 'PAUSED' 30 | }; 31 | 32 | return this; 33 | } 34 | 35 | get hash () { 36 | return ``; // TODO: real hash 37 | } 38 | 39 | get id () { 40 | return ''; // TODO: Fabric ID 41 | } 42 | 43 | get txid () { 44 | return ``; // TODO: bitcoin txid 45 | } 46 | 47 | signAsHolder () { 48 | const hash = crypto.createHash('sha256').update('').digest('hex'); 49 | this.signature = this.holder.sign(hash); 50 | return this; 51 | } 52 | } 53 | 54 | module.exports = BitcoinTransaction; 55 | -------------------------------------------------------------------------------- /tests/fabric.weave.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Weave = require('../types/weave'); 4 | const assert = require('assert'); 5 | 6 | describe('@fabric/core/types/weave', function () { 7 | describe('Weave', function () { 8 | it('is available from @fabric/core', function () { 9 | assert.strictEqual(Weave instanceof Function, true); 10 | }); 11 | 12 | it('can construct an empty weave', async function () { 13 | let weave = new Weave(); 14 | assert.ok(weave); 15 | assert.strictEqual(weave._state.status, 'initialized'); 16 | }); 17 | 18 | it('can construct a known weave', async function () { 19 | let weave = new Weave(['foo', 'bar']); 20 | assert.ok(weave); 21 | assert.strictEqual(weave._state.root, '906b5aaf65ae98f8c98848de5e81ba865659f16fd53aefa4c78b34176f068079'); // TODO: wat? 22 | }); 23 | }); 24 | 25 | describe('_generateLayer', function () { 26 | it('can generate a known layer', async function () { 27 | const weave = new Weave(['Hello,', 'World!']); 28 | const layer = await weave._generateLayer(); 29 | assert.ok(weave); 30 | assert.strictEqual(weave.root.toString('hex'), 'f4d6428b2c8eac8083ac6da97a996284b23d7482a35a2ced481205d96e7792ea'); 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | _Convenient tool for keeping things tidy._ 3 | 4 | ## Quick Start 5 | _Include this file in your repo to keep uses of `git status` quite clean._ 6 | 7 | ## _ 8 | _Used as a string separator when reading this file. :)_ 9 | 10 | ## Ignore: 11 | ### Logs 12 | logs 13 | *.log 14 | 15 | ### Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | 20 | ### Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | ### Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | ### node-waf configuration 27 | .lock-wscript 28 | 29 | ### Compiled binary addons (http://nodejs.org/api/addons.html) 30 | build/Release 31 | 32 | ### Dependency directory 33 | #### https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 34 | node_modules 35 | 36 | ### Service Output 37 | # GDP of NYC? (@lel) 38 | .nyc-output 39 | # Gitbook Output 40 | _book 41 | # Barebones App 42 | assets/app.js 43 | # Service Files; Minified service file that, if included, runs 44 | assets/service.js 45 | # Minified fabric.js bundle 46 | assets/fabric.min.js 47 | 48 | # Hide bitcoin node blocks 49 | stores 50 | 51 | # Nix 52 | result* 53 | 54 | # IntelliJ 55 | .idea 56 | 57 | _book 58 | 59 | # Pesky Mac Stuff 60 | .DS_Store 61 | -------------------------------------------------------------------------------- /assets/docs.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?js= title ?> · Docs 6 | 7 | 8 | 11 | 12 | 13 | 19 | 20 | 21 |

22 | 23 |
24 | 25 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ACTORS.md: -------------------------------------------------------------------------------- 1 | # Actors 2 | The `Actor` class is the parent class of most `@fabric/core` components; you 3 | can use it for any Fabric-enabled application. 4 | 5 | ## Role 6 | The `Actor` is the basis for most, if not all, native types in the Fabric Compute Space. It is an `EventEmitter` and will typically emit the following events: 7 | 8 | 1. `message` 9 | 2. `debug` 10 | 3. `log` 11 | 4. `warning` 12 | 5. `error` 13 | 14 | Some Actor types (such as `Service`) also provide `beat`, `tick`, or `state` events. 15 | 16 | ## Behavior 17 | The `Actor` is a standard ECMAScript object with the following properties: 18 | ``` 19 | id: String 20 | state: Object 21 | ``` 22 | 23 | ## Example 24 | Interacting with a Fabric Actor: 25 | ```js 26 | // Use `npm i @fabric/core` first 27 | const Actor = require('@fabric/core/types/actor'); 28 | const actor = new Actor({ foo: 'bar' }); 29 | 30 | // Listen for events 31 | actor.on('message', (message) => { 32 | console.log('Message from Actor:', message); 33 | }); 34 | 35 | // Adopt a set of changes 36 | actor.adopt([ 37 | { op: 'replace', path: '/baz', value: 'plop' } 38 | ]); 39 | 40 | console.log('My Actor:', JSON.stringify(actor, null, ' ')); 41 | ``` 42 | 43 | Output: 44 | 45 | ``` 46 | My Actor: { 47 | "foo": "bar", 48 | "baz": "bop" 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | // # Examples with Fabric 2 | // Fabric is like an operating system for the distributed web. It manages 3 | // application state, storage, and network interactions behind the scenes while 4 | // providing your application with a convenient event-oriented interface. 5 | // 6 | // We use [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) to improve error handling and debugging, so we recommend you do the same. 7 | 'use strict'; 8 | 9 | // ## Importing Fabric 10 | // Fabric is easily imported into existing applications. When using JavaScript, 11 | // use the `require` semantic to import as a library. 12 | const Fabric = require('@fabric/core'); 13 | 14 | // Most interactions with Fabric are asynchronous, so let's define our program's 15 | // primary behavior. 16 | async function main () { 17 | // 1. Create an instance of Fabric... 18 | let app = new Fabric(); 19 | 20 | // 2. Add some data... 21 | await app._POST(`/inscriptions`, { input: 'Hello, world!' }); 22 | 23 | // 3. Output some results! 24 | console.log('app:', app); 25 | } 26 | 27 | main(); 28 | // Now that we've defined our program, let's run it to see the results. 29 | 30 | // ### Next Steps 31 | // That's all there is to it! Now, [on to the API Explorer](https://dev.fabric.pub/docs)! 32 | -------------------------------------------------------------------------------- /tests/fabric.channel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Actor = require('../types/actor'); 5 | const Channel = require('../types/channel'); 6 | 7 | const sample = {}; 8 | 9 | describe('@fabric/core/types/channel', function () { 10 | describe('Channel', function () { 11 | it('is available from @fabric/core', function () { 12 | assert.equal(Channel instanceof Function, true); 13 | }); 14 | 15 | it('can instantiate from sample data', function (done) { 16 | async function test () { 17 | const channel = new Channel(sample); 18 | assert.ok(channel); 19 | done(); 20 | } 21 | 22 | test(); 23 | }); 24 | 25 | it('can call add', function (done) { 26 | async function test () { 27 | const channel = new Channel(sample); 28 | channel.add(1); 29 | assert.ok(channel); 30 | done(); 31 | } 32 | 33 | test(); 34 | }); 35 | 36 | it('can call fund', function (done) { 37 | async function test () { 38 | const channel = new Channel(sample); 39 | 40 | await channel.fund({ 41 | raw: Actor.randomBytes(32) 42 | }); 43 | 44 | assert.ok(channel); 45 | done(); 46 | } 47 | 48 | test(); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /SETTINGS.md: -------------------------------------------------------------------------------- 1 | # Fabric Settings 2 | Fabric works best when installed globally (or on your `$PATH`). For most use 3 | cases, we can install Fabric with simply: 4 | 5 | > `$ npm i -g FabricLabs/fabric` 6 | > `$ fabric --keygen` 7 | 8 | This should create (or read) a folder `~/.fabric` with a JSON configuration 9 | file. Take care, as this file is not (currently) encrypted. 10 | 11 | ## Using Environment Variables 12 | You may use the following environment variables for simple configuration: 13 | 14 | - `FABRIC_SEED` to specify a BIP 39 seed phrase for your Fabric node 15 | - `FABRIC_PORT` to specify the TCP port upon which to listen 16 | 17 | ### WARNING: TODO 18 | - `FABRIC_PASSPHRASE` to specify the derivation passphrase 19 | 20 | ## Using Your Own Full Node 21 | ### Setup Bitcoin Core 22 | First, we must ensure Bitcoin Core's RPC interface is available to us. We 23 | will rely on it to provide consensus over the Bitcoin blockchain. 24 | 25 | 1. Install Bitcoin Core `0.21.1` 26 | 2. Add `rpcuser` and `rpcpassword` to `bitcoin.conf` 27 | 3. Run `bitcoind -regtest -server -txindex=1` 28 | 29 | ### Configure Fabric 30 | In your local Fabric repository, complete the following: 31 | 32 | 1. Configure `settings/local.json` with your Bitcoin RPC URL 33 | 2. Ensure global availability: `npm i -g` 34 | 3. Run `fabric chat` 35 | -------------------------------------------------------------------------------- /types/queue.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const merge = require('lodash.merge'); 4 | const Actor = require('./actor'); 5 | 6 | class Queue extends Actor { 7 | constructor (settings = {}) { 8 | super(settings); 9 | 10 | this.settings = merge({ 11 | workers: 1 12 | }, settings); 13 | 14 | this._state = { 15 | jobs: {}, 16 | status: 'STOPPED' 17 | }; 18 | 19 | this._methods = {}; 20 | 21 | return this; 22 | } 23 | 24 | async start () { 25 | await this._registerMethod('verify', async function (...params) { 26 | 27 | }); 28 | } 29 | 30 | async _registerMethod (name, contract) { 31 | if (this._methods[name]) return this._methods[name]; 32 | // TODO: bind state? 33 | this._methods[name] = contract.bind({}); 34 | return this._methods[name]; 35 | } 36 | 37 | async _addJob (job) { 38 | if (!job.id) job = new Actor(job); 39 | // TODO: reduce lookups 40 | if (this._state.jobs[job.id]) return this._state.jobs[job.id]; 41 | this._state.jobs[job.id] = job; 42 | this.emit('job', this._state.jobs[job.id]); 43 | return this._state.jobs[job.id]; 44 | } 45 | 46 | async _takeJob (job) { 47 | 48 | } 49 | 50 | async _completeJob (job) { 51 | 52 | } 53 | 54 | async _failJob (job) { 55 | 56 | } 57 | } 58 | 59 | module.exports = Queue; 60 | -------------------------------------------------------------------------------- /contracts/chat.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Settings 4 | const settings = require('../settings/local'); 5 | 6 | // Fabric Types 7 | const CLI = require('../types/cli'); 8 | 9 | // Services 10 | // const Matrix = require('@fabric/matrix'); 11 | 12 | // Program Definition 13 | async function OP_CHAT () { 14 | if (!this.environment.wallet) { 15 | console.error('No wallet found! Set up your Fabric wallet by running:'); 16 | console.error('\tfabric setup'); 17 | process.exit(1); 18 | } 19 | 20 | // Fabric CLI 21 | const chat = new CLI(settings); // TODO: this.settings 22 | 23 | chat.on('error', (error) => { 24 | console.error('[FABRIC:CHAT]', '[ERROR]', error); 25 | }); 26 | 27 | // Use local wallet 28 | chat.attachWallet(this.environment.wallet); 29 | 30 | // Assume identity 31 | // TODO: remove, re-work Peer and Wallet key import in CLI 32 | chat.assumeIdentity(this.environment.wallet.settings.key); 33 | 34 | // ## Services 35 | // TODO: reconcile API wth @fabric/doorman as appears at: https://github.com/FabricLabs/doorman 36 | // chat._registerService('matrix', Matrix); 37 | // chat._registerService('rpg', RPG); 38 | 39 | await chat.start(); 40 | 41 | return JSON.stringify({ 42 | id: chat.id, 43 | wallet: this.environment.wallet.id 44 | }); 45 | } 46 | 47 | // Module 48 | module.exports = OP_CHAT; 49 | -------------------------------------------------------------------------------- /scripts/app.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | // Settings 5 | const settings = require('../settings/default'); 6 | 7 | // Fabric Types 8 | const App = require('../types/app'); 9 | 10 | // Fabric Services 11 | const Lightning = require('../services/lightning'); 12 | 13 | // Functions 14 | const _handleMessage = require('../functions/_handleMessage'); 15 | const _handleWarning = require('../functions/_handleWarning'); 16 | const _handleError = require('../functions/_handleError'); 17 | 18 | async function main () { 19 | // Instantiate Application 20 | const app = new App(settings); 21 | 22 | // Define Resources 23 | await app.define('Example', { 24 | components: { 25 | list: 'example-list', 26 | view: 'example-view' 27 | } 28 | }); 29 | 30 | // Register Services 31 | await app._registerService('lightning', Lightning); 32 | 33 | // Attach Listeners 34 | app.on('message', _handleMessage); 35 | app.on('warning', _handleWarning); 36 | app.on('error', _handleError); 37 | 38 | // Start the Application 39 | await app.start(); 40 | 41 | // Render the UI 42 | return app.render(); 43 | } 44 | 45 | main().catch((exception) => { 46 | console.error('[SCRIPTS:MAIN]', 'Main Process Exception:', exception); 47 | }).then((output) => { 48 | console.log('[SCRIPTS:MAIN]', 'Main Process Output:', output); 49 | }); 50 | -------------------------------------------------------------------------------- /GOALS.md: -------------------------------------------------------------------------------- 1 | # Fabric Engineering Goals 2 | 3 | 1. Complexity is the enemy. Prefer simplicity. 4 | 2. Make it work, make it right, make it fast. In that order. 5 | 3. Improve access to human liberty with every contribution. 6 | 7 | ## Alternatives 8 | 1. Secure Sovereignty 9 | 2. Equivalent (or superior) Experience 10 | 3. Eliminate Trusted Third Parties 11 | 12 | ## Mindset 13 | Precision engineering requires long periods of intense focus. We seek healthy work/life balances, 14 | especially surrounding R&D related activities (Fabric Labs). Striving for excellence is paramount, 15 | and no mission succeeds without a clearly-defined set of goals. 16 | 17 | ## Current Goals 18 | These are our immediate goals: 19 | 20 | - [ ] Find all TODO items (run script, check diff) 21 | - [ ] Audit all documentation 22 | - [ ] Check all hyperlinks on `npm run dev` 23 | - [ ] 100% test coverage 24 | - [ ] Completion of 1 or more of our #projects: https://chat.fabric.pub/#/room/#projects:fabric.pub 25 | 26 | ## Credits 27 | Helping out grants you a named credit, as listed below. We aggregate these credits in 28 | all of the products we produce, including updates to existing applications. Feel free to add 29 | your name in any pull request you submit! 30 | 31 | ### Contributors 32 | - @martindale — Eric Martindale 33 | - @chrisinajar - Christopher Vickery 34 | - @melnx — Alexey Melnichenko 35 | -------------------------------------------------------------------------------- /tests/fabric.capability.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Capability = require('../types/capability'); 5 | const Identity = require('../types/identity'); 6 | const Signer = require('../types/signer'); 7 | 8 | const sample = { 9 | type: 'CREATE_BLOCK' 10 | }; 11 | 12 | describe('@fabric/core/types/capability', function () { 13 | describe('Capability', function () { 14 | it('is available from @fabric/core', function () { 15 | assert.equal(Capability instanceof Function, true); 16 | }); 17 | 18 | it('can instantiate from sample data', function (done) { 19 | async function test () { 20 | const capability = new Capability(sample); 21 | assert.ok(capability); 22 | done(); 23 | } 24 | 25 | test(); 26 | }); 27 | 28 | it('can generate a token for an identity', function (done) { 29 | async function test () { 30 | const identity = new Identity(sample); 31 | const capability = new Capability(sample); 32 | const token = await capability._generateToken(); 33 | 34 | assert.ok(identity); 35 | assert.ok(capability); 36 | assert.ok(token); 37 | 38 | assert.strictEqual(token.macaroon.s64, '2RbOb5ti3EoIDOXUpmCVZHHxm4YNpCQrCFJyczHBAz0'); 39 | 40 | done(); 41 | } 42 | 43 | test(); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /tests/fabric.codec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const playnet = require('../settings/playnet'); 5 | 6 | const Codec = require('../types/codec'); 7 | const Hash256 = require('../types/hash256'); 8 | 9 | describe('@fabric/core/types/codec', function () { 10 | describe('Codec', function () { 11 | it('is available from @fabric/core', function () { 12 | assert.strictEqual(Codec instanceof Function, true); 13 | }); 14 | 15 | it('can instantiate smoothly', async function () { 16 | const codec = new Codec(); 17 | assert.ok(codec); 18 | }); 19 | 20 | it('has the correct pubkey', async function () { 21 | const codec = new Codec(playnet); 22 | assert.ok(codec); 23 | assert.strictEqual(codec.key.pubkey, '0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71'); 24 | }); 25 | 26 | it('can encode data', async function () { 27 | const codec = new Codec(playnet); 28 | const blob = codec.encode('Hello, world!'); 29 | assert.ok(blob); 30 | }); 31 | 32 | xit('can decode data', async function () { 33 | const encoder = new Codec(playnet); 34 | const decoder = new Codec(playnet); 35 | 36 | const blob = encoder.encode('Hello, world!'); 37 | const data = decoder.decode(blob); 38 | 39 | assert.ok(data); 40 | assert.strictEqual(data, 'Hello, world!'); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /docs/overview.dot: -------------------------------------------------------------------------------- 1 | digraph FabricDesignOverview { 2 | rankdir = BT 3 | 4 | subgraph cluster_network { 5 | label = "Verifier Cycle" 6 | 7 | subgraph cluster_bitcoin { 8 | label = "Bitcoin Blockchain" 9 | node [shape=record] 10 | blockchain [label=" block 0 | block 1 | block ... | block n"] 11 | } 12 | 13 | subgraph cluster_circuits { 14 | label = "Verifier Circuit" 15 | 16 | subgraph cluster_lightning { 17 | label = "Off-chain UTXOs" 18 | node [shape=record] 19 | state [label=" state 0 | state 1 | state ... | state n"] 20 | } 21 | 22 | subgraph cluster_fabric { 23 | label = "Verifier Circuits" 24 | node [shape=record] 25 | fabric [label=" state 0 | state 1 | state ... | state n"] 26 | } 27 | 28 | subgraph cluster_channels { 29 | label = "Channel Clusters" 30 | 31 | "Contract Definition" -> 32 | "Circuit Generator" ->{ 33 | "alice:bob:c0" 34 | "alice:bob:c1" 35 | "alice:bob:c2" 36 | "alice:bob:cn" 37 | } 38 | } 39 | } 40 | 41 | blockchain:b0 -> state:l0 -> fabric:v0 [label = " initial state"] 42 | fabric:v1 -> state:ls [label = " Byzantine State"] 43 | state:ls -> blockchain:bn [label = " justice"] 44 | fabric:vn -> state:ln -> blockchain:bn [label = " final state"] 45 | } 46 | } -------------------------------------------------------------------------------- /contracts/classes.dot: -------------------------------------------------------------------------------- 1 | digraph FabricClasses { 2 | label = "Fabric Class Inheritances" 3 | rankdir = "TB" 4 | 5 | subgraph cluster_generics { 6 | label = "Generics" 7 | "Object" 8 | "EventEmitter" 9 | } 10 | 11 | subgraph cluster_core { 12 | label = "Public API" 13 | "Actor" 14 | "Block" 15 | "Bitcoin" 16 | "Chain" 17 | "Channel" 18 | "Contract" 19 | "Environment" 20 | "Key" 21 | "Lightning" 22 | "Message" 23 | "Peer" 24 | "Reader" 25 | "Service" 26 | "Signer" 27 | "Transaction" 28 | "Tree" 29 | "Wallet" 30 | } 31 | 32 | subgraph cluster_candidates { 33 | label = "Candidates" 34 | "App" 35 | "CLI" 36 | } 37 | 38 | subgraph cluster_legacy { 39 | label = "Legacy" 40 | "Entity" 41 | } 42 | 43 | "Actor" -> { 44 | "Block" 45 | "Chain" 46 | "Message" 47 | "Service" 48 | "Signer" 49 | "Transaction" 50 | "Tree" 51 | } 52 | 53 | "App" -> { 54 | "CLI" 55 | } 56 | 57 | "Contract" -> { 58 | "Crowdfund" 59 | "Distribution" 60 | "Federation" 61 | } 62 | 63 | "Entity" -> "Environment" 64 | "EventEmitter" -> { 65 | "Actor" 66 | "Entity" 67 | "Reader" 68 | } 69 | 70 | "Object" -> "EventEmitter" 71 | "Object" -> "Key" 72 | 73 | "Service" -> { 74 | "App" 75 | "Bitcoin" 76 | "Channel" 77 | "Contract" 78 | "Lightning" 79 | "Peer" 80 | "Wallet" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /scripts/classtree.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = process.argv[2]; 5 | 6 | let files = fs.readdirSync(path); 7 | let classExtends = {}; 8 | 9 | for (let i = 0; i < files.length; i++) { 10 | if (!files[i].includes('.js')) continue; 11 | let text = fs.readFileSync(path + "/" + files[i], 'utf8'); 12 | let ci = text.indexOf('class '); 13 | 14 | let decl = ''; 15 | if (ci >= 0) { 16 | for (var j = ci; j < text.length; j++) { 17 | if (text[j] === '{') break; 18 | decl += text[j]; 19 | } 20 | } 21 | 22 | decl = decl.trim(); 23 | if (!decl) continue; 24 | 25 | let parts = decl.split(' '); 26 | if (parts.length > 4) continue; 27 | 28 | let className = parts[1]; 29 | let extendsClassName = null; 30 | 31 | if (parts.includes('extends')) { 32 | let classPath = parts[3].split('.'); 33 | extendsClassName = classPath[classPath.length - 1]; 34 | } 35 | 36 | classExtends[className] = extendsClassName; 37 | if (!classExtends[extendsClassName]) classExtends[extendsClassName] = null; 38 | } 39 | 40 | classExtends['EventEmitter'] = null; 41 | 42 | function buildSubtree(subtree, parent=null) { 43 | for (let k in classExtends) { 44 | if (k === 'null' || k === null) continue; 45 | if (classExtends[k] === parent) { 46 | subtree[k] = {}; 47 | buildSubtree(subtree[k], k); 48 | } 49 | } 50 | } 51 | 52 | buildSubtree(tree); 53 | console.log(JSON.stringify(tree, null, 2)); 54 | -------------------------------------------------------------------------------- /settings/playnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@network/playnet", 3 | "network": "testnet", 4 | "anchor": "BTC", 5 | "peers": [], 6 | "mode": "rpc", 7 | "servers": [ 8 | "http://YOUR_USERNAME:YOUR_PASSWORD@localhost:18443" 9 | ], 10 | "currencies": [ 11 | { 12 | "name": "BTCA", 13 | "symbol": "BTCA", 14 | "service": "btca" 15 | }, { 16 | "name": "BTCB", 17 | "symbol": "BTCB", 18 | "service": "btcb" 19 | } 20 | ], 21 | "bitcoin": { 22 | "address": "bcrt1qr26ree4yhcnxsn7rdxj5hgwf6awz2jmwe8t9q6" 23 | }, 24 | "btca": { 25 | "name": "BTCA", 26 | "mode": "rpc", 27 | "servers": [ 28 | "http://YOUR_USERNAME:YOUR_PASSWORD@localhost:18443" 29 | ] 30 | }, 31 | "btcb": { 32 | "name": "BTCB", 33 | "mode": "rpc", 34 | "servers": [ 35 | "http://YOUR_USERNAME:YOUR_PASSWORD@localhost:19443" 36 | ] 37 | }, 38 | "key": { 39 | "seed": "letter drastic census knock shield matter crime demand gloom echo romance lizard zebra deliver baby key tackle fire update please sketch coconut balance able", 40 | "public": "0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71", 41 | "xprv": "xprv9s21ZrQH143K2jKS8iCu5QQg34zf7k5h1nfJZbuWQxDDSRmyLxt6BmJARp1SwfGtMAwPNEeQmUJpD5DosB4f3YxaJZiUS2wq6TzsNzFiEjJ", 42 | "xpub": "xpub661MyMwAqRbcFDPuEjjuSYMQb6q9XCoYP1auMzK7yHkCKE77tWCLjZceH4xFT1ZCc3FKpeMnii9JMLHp7n9dvDvz8MJ1CYge2digpGRjk7D" 43 | }, 44 | "validators": [] 45 | } 46 | -------------------------------------------------------------------------------- /assets/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "@id": "bc128b68d26860b266226a5f4d435b44764beb899026bf13ff600facd3f18782", 3 | "id": "bc128b68d26860b266226a5f4d435b44764beb899026bf13ff600facd3f18782", 4 | "@data": { 5 | "Asset": { 6 | "name": "Asset", 7 | "routes": { 8 | "list": "/assets", 9 | "view": "/assets/:id" 10 | } 11 | }, 12 | "Index": { 13 | "name": "Index", 14 | "routes": { 15 | "list": "/" 16 | }, 17 | "components": { 18 | "list": "fabric-index" 19 | }, 20 | "data": {} 21 | }, 22 | "Widget": { 23 | "name": "Widget", 24 | "properties": { 25 | "name": { 26 | "type": "String", 27 | "maxLength": 100 28 | } 29 | }, 30 | "routes": { 31 | "list": "/widgets", 32 | "view": "/widgets/:id" 33 | } 34 | } 35 | }, 36 | "Asset": { 37 | "name": "Asset", 38 | "routes": { 39 | "list": "/assets", 40 | "view": "/assets/:id" 41 | } 42 | }, 43 | "Index": { 44 | "name": "Index", 45 | "routes": { 46 | "list": "/" 47 | }, 48 | "components": { 49 | "list": "fabric-index" 50 | }, 51 | "data": {} 52 | }, 53 | "Widget": { 54 | "name": "Widget", 55 | "properties": { 56 | "name": { 57 | "type": "String", 58 | "maxLength": 100 59 | } 60 | }, 61 | "routes": { 62 | "list": "/widgets", 63 | "view": "/widgets/:id" 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /docs/hello-world.md: -------------------------------------------------------------------------------- 1 | # Hello World with Fabric 2 | Fabric offers a familiar API for most web developers: 3 | 4 | ```js 5 | import App from 'fabric'; 6 | const app = new App(); 7 | 8 | app.start(); 9 | ``` 10 | 11 | That's it. That's all there is to it. By running the above code, you should 12 | now have a running application on your desktop. 13 | 14 | Of course, we'll want to add more functionality. To do that, let's add some 15 | [Resources][resources]. 16 | 17 | ## Adding Resources 18 | Fabric uses a simple JSON format to configure resources that it makes accessible 19 | to your application. 20 | 21 | To add one, simply use `app.define(name, definition)`, where `name` is the 22 | human-friendly name for the resource, and `definition` is the JSON-encoded 23 | representation. 24 | 25 | ```js 26 | await app.define('Person', { 27 | attributes: { 28 | username: String 29 | } 30 | }); 31 | ``` 32 | 33 | Note the use of the `await` keyword here, as it indicates we want to wait for a 34 | response. For documentation, check [the `Resource` API definition][resources]. 35 | 36 | Just as before, start your application and you'll now see something like this: 37 | 38 | ![Fabric Application with One Resource](...) 39 | 40 | ## Configuration 41 | By default, Fabric Applications expose one Resource, the `Asset` class. Each 42 | additional Resource added is served through the Fabric interface, operating 43 | under the rules of its original definition. 44 | 45 | [resources]: https://api.fabric.fm/Resource.html 46 | -------------------------------------------------------------------------------- /tests/fabric.contract.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Contract = require('../types/contract'); 5 | 6 | const sample = {}; 7 | 8 | describe('@fabric/core/types/contract', function () { 9 | describe('Contract', function () { 10 | it('is available from @fabric/core', function () { 11 | assert.equal(Contract instanceof Function, true); 12 | }); 13 | 14 | it('can instantiate from sample data', function (done) { 15 | async function test () { 16 | const contract = new Contract(sample); 17 | assert.ok(contract); 18 | done(); 19 | } 20 | 21 | test(); 22 | }); 23 | 24 | it('can start and stop', function (done) { 25 | async function test () { 26 | const contract = new Contract(sample); 27 | contract.start(); 28 | contract.stop(); 29 | assert.ok(contract); 30 | done(); 31 | } 32 | 33 | test(); 34 | }); 35 | 36 | it('can publish a contract', function (done) { 37 | async function test () { 38 | const contract = new Contract(sample); 39 | contract.on('message', (msg) => { 40 | switch (msg['@type']) { 41 | default: 42 | case 'CONTRACT_PUBLISH': 43 | assert.ok(contract); 44 | assert.ok(msg); 45 | done(); 46 | break; 47 | } 48 | }); 49 | contract.deploy(); 50 | } 51 | 52 | test(); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /examples/http.js: -------------------------------------------------------------------------------- 1 | // # Exposing ARCs with HTTP 2 | // Fabric makes it easy to publish applications to the Web, 3 | // giving downstream users access to a hosted instance of the 4 | // application. 5 | // 6 | // By using `@fabric/http` we can import an existing Fabric 7 | // application, and run an HTTP server which exposes a rendered 8 | // HTML user interface, complete with progressive enhancement of 9 | // features such as real-time updates and hardware-based key 10 | // management. 11 | // 12 | // ## Quick Start 13 | 14 | // Import the `@fabric/http` library: 15 | const HTTP = require('@fabric/http'); 16 | 17 | // Define the `main` program: 18 | async function main () { 19 | // Create an instance of a [Server](https://dev.fabric.pub/docs/service.html): 20 | const server = new HTTP.Server(); 21 | 22 | // Define a [Resource](https://dev.fabric.pub/docs/resource.html): 23 | await server.define('Person', { 24 | name: 'Person', 25 | properties: { 26 | username: { type: String , maxLength: 55 } 27 | }, 28 | routes: { 29 | list: '/people', 30 | view: '/people/:id' 31 | } 32 | }); 33 | 34 | // Start the Server instance: 35 | await server.start(); 36 | } 37 | 38 | // Run Program: 39 | main().catch((exception) => { 40 | console.log('[EXAMPLES:HTTP]', 'HTTP Exception:', exception); 41 | }); 42 | 43 | // That's it! You can now visit `https://localhost:` to interact 44 | // using the HTTP interface for your program. 45 | // 46 | // Take a look at the other examples to learn more! 47 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # Fabric: an experimental p2p framework 3 | * Providing an interface to Fabric network, this file defines the available 4 | * components and abstractions used when relying on this library. 5 | */ 6 | 'use strict'; 7 | 8 | const Fabric = require('./types/fabric'); 9 | 10 | /** 11 | * Default interface to {@link Fabric}. Provides immutable types for all 12 | * elements of the `components` option. 13 | * @property {Configuration} config Initial {@link Vector}. 14 | * @property {Map} config.components Transformation function of `Σ ⇒ Δ`. 15 | */ 16 | class FabricApplication extends Fabric { 17 | /** 18 | * Create a new instance of the Fabric Application. 19 | * @param {Object} [config] Configuration object. 20 | * @param {Object} [config.store] Path to local storage. 21 | * @param {Object} [config.components] Map of components. 22 | * @param {Object} [config.components.list] Name of "list" component. 23 | * @param {Object} [config.components.view] Name of "view" component. 24 | * @return {FabricApplication} 25 | */ 26 | constructor (config) { 27 | super(config); 28 | 29 | // Store the configuration 30 | this.config = Object.assign({ 31 | store: `./stores/${this.constructor.name.toLowerCase()}` 32 | }, config); 33 | 34 | return this; 35 | } 36 | 37 | /** 38 | * Draw the application to canvas (display). 39 | * @return {Mixed} 40 | */ 41 | render () { 42 | return ``; 43 | } 44 | } 45 | 46 | module.exports = FabricApplication; 47 | -------------------------------------------------------------------------------- /tests/fabric.hkdf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const HKDF = require('../types/hkdf'); 4 | const assert = require('assert'); 5 | 6 | // Test Vectors (cut to 32 bytes) 7 | const vectors = { 8 | ikm: Buffer.from('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', 'hex'), 9 | salt: Buffer.from('000102030405060708090a0b0c', 'hex'), 10 | info: Buffer.from('f0f1f2f3f4f5f6f7f8f9', 'hex'), 11 | prk: Buffer.from('077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5', 'hex'), 12 | okm: Buffer.from('3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf', 'hex') 13 | }; 14 | 15 | describe('@fabric/core/types/hkdf', function () { 16 | describe('HKDF', function () { 17 | it('is a constructor', function () { 18 | assert.equal(HKDF instanceof Function, true); 19 | }); 20 | 21 | it('can generate correct PRK', function () { 22 | let hkdf = new HKDF({ 23 | initial: vectors.ikm.toString(), 24 | salt: vectors.salt.toString() 25 | }); 26 | 27 | assert.ok(hkdf); 28 | assert.equal(hkdf.size, 32); 29 | assert.deepEqual(hkdf.prk, vectors.prk); 30 | }); 31 | 32 | it('can generate correct HKDF output', function () { 33 | let hkdf = new HKDF({ 34 | initial: vectors.ikm.toString(), 35 | salt: vectors.salt.toString() 36 | }); 37 | 38 | assert.ok(hkdf); 39 | assert.equal(hkdf.size, 32); 40 | assert.deepEqual(hkdf.prk, vectors.prk); 41 | assert.deepEqual(hkdf.derive(vectors.info), vectors.okm); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /tests/fabric.transition.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const assert = require('assert'); 4 | const Transition = require('../types/transition'); 5 | 6 | const stateSample = [ 7 | { id: 1, something: 1 }, 8 | { id: 2, something: 2 }, 9 | { id: 3, something: 3 }, 10 | ]; 11 | 12 | describe('@fabric/core/types/transition', function () { 13 | describe('Transition', function () { 14 | it('can fromTarget(target)', async () => { 15 | let transition = new Transition({ 16 | origin: stateSample[0], 17 | target: stateSample[1], 18 | }); 19 | 20 | let result = transition.fromTarget(stateSample[2]); 21 | 22 | assert.equal(result.data.origin, '44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a'); 23 | assert.equal(result.data.target, 'e44d57fe4579390236fc75367f8213f67da1b1c7810f3f0868818dc9d49c5984'); 24 | }); 25 | 26 | it('can between(origin,target)', async () => { 27 | let result = Transition.between(stateSample[0], stateSample[1]); 28 | let changes = result.data.changes; 29 | let expected = [ 30 | { 31 | 'op': 'replace', 32 | 'path': '/something', 33 | 'value': 2, 34 | }, 35 | { 36 | 'op': 'replace', 37 | 'path': '/id', 38 | 'value': 2, 39 | } 40 | ]; 41 | 42 | for (var c in changes) { 43 | let change = changes[c]; 44 | for (var p in change) { 45 | assert.equal(changes[c][p], expected[c][p]); 46 | } 47 | } 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /examples/cluster/node-d.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SEED = process.env.SEED; 4 | const PORT = process.env.PORT || 3338; 5 | 6 | // Dependencies 7 | const Peer = require('../../types/peer'); 8 | const Message = require('../../types/message'); 9 | 10 | async function main () { 11 | const peer = new Peer({ 12 | port: PORT, 13 | listen: true, 14 | wallet: { 15 | seed: SEED 16 | }, 17 | peers: ['localhost:3337'] 18 | }); 19 | 20 | // Core functionality (wait for peer, send message) 21 | peer.on('peer:candidate', async function (peer) { 22 | console.log('[EXAMPLES:RELAY]', 'Peer "D" emitted "peer:candidate" event:', peer); 23 | 24 | if (peer.id === PEER_ID) { 25 | console.warn('[EXAMPLES:RELAY]', 'Peer event was destination peer!'); 26 | console.warn('[EXAMPLES:RELAY]', 'Known peers:', peer.peers); 27 | 28 | // Send Message 29 | let message = Message.fromVector(['Generic', 'Hello, world!']); 30 | await peer.broadcast(message); 31 | } 32 | }); 33 | 34 | // Listeners 35 | peer.on('message', async function handleHubMessage (msg) { 36 | console.log('[EXAMPLES:RELAY]', 'Got message on origin:', msg.type, msg.body.toString('utf8')); 37 | }); 38 | 39 | // Start component services 40 | console.warn('[EXAMPLES:RELAY]', 'Starting Peer "D"...'); 41 | await peer.start(); 42 | console.log('[EXAMPLES:RELAY]', 'Peer "D" started!'); 43 | } 44 | 45 | main().catch(function exceptionHandler (exception) { 46 | console.error('[EXAMPLES:RELAY]', 'Main process threw Exception:', exception); 47 | }); -------------------------------------------------------------------------------- /examples/cluster/node-e.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SEED = process.env.SEED; 4 | const PORT = process.env.PORT || 3339; 5 | 6 | // Dependencies 7 | const Peer = require('../../types/peer'); 8 | const Message = require('../../types/message'); 9 | 10 | async function main () { 11 | const peer = new Peer({ 12 | port: PORT, 13 | listen: true, 14 | wallet: { 15 | seed: SEED 16 | }, 17 | peers: ['localhost:3337'] 18 | }); 19 | 20 | // Core functionality (wait for peer, send message) 21 | peer.on('peer:candidate', async function (peer) { 22 | console.log('[EXAMPLES:RELAY]', 'Peer "E" emitted "peer:candidate" event:', peer); 23 | 24 | if (peer.id === PEER_ID) { 25 | console.warn('[EXAMPLES:RELAY]', 'Peer event was destination peer!'); 26 | console.warn('[EXAMPLES:RELAY]', 'Known peers:', peer.peers); 27 | 28 | // Send Message 29 | let message = Message.fromVector(['Generic', 'Hello, world!']); 30 | await peer.broadcast(message); 31 | } 32 | }); 33 | 34 | // Listeners 35 | peer.on('message', async function handleHubMessage (msg) { 36 | console.log('[EXAMPLES:RELAY]', 'Got message on origin:', msg.type, msg.body.toString('utf8')); 37 | }); 38 | 39 | // Start component services 40 | console.warn('[EXAMPLES:RELAY]', 'Starting Peer "E"...'); 41 | await peer.start(); 42 | console.log('[EXAMPLES:RELAY]', 'Peer "E" started!'); 43 | } 44 | 45 | main().catch(function exceptionHandler (exception) { 46 | console.error('[EXAMPLES:RELAY]', 'Main process threw Exception:', exception); 47 | }); -------------------------------------------------------------------------------- /settings/local.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Contracts 4 | // TODO: test env variables with OP_TEST 5 | const OP_TEST = require('../contracts/test'); 6 | 7 | // Settings 8 | module.exports = { 9 | name: process.env['NAME'], 10 | namespace: process.env['NAMESPACE'], 11 | seed: process.env['FABRIC_SEED'], 12 | xprv: process.env['FABRIC_XPRV'], 13 | xpub: process.env['FABRIC_XPUB'], 14 | port: process.env['FABRIC_PORT'], 15 | // Strict Functions 16 | functions: { 17 | OP_TEST: JSON.stringify(OP_TEST) 18 | }, 19 | // TODO: regtest, playnet, signet, testnet, mainnet (in order) 20 | network: 'playnet', 21 | debug: false, 22 | // TODO: test `true` 23 | fullnode: false, 24 | // Open listener? 25 | listen: true, 26 | // Render UI? 27 | render: true, 28 | // Open outbound connections? 29 | peering: true, 30 | // Known Peers 31 | peers: [ 32 | '0223cffd5e94da3c8915c6b868f06d15183c1aeffad8ddf58fcb35a428e3158e71@hub.fabric.pub:7777' 33 | ], 34 | // Bitcoin 35 | bitcoin: { 36 | host: 'localhost', 37 | port: 8443, 38 | username: 'polaruser', 39 | password: 'polarpass', 40 | secure: false 41 | }, 42 | // Lightning 43 | lightning: { 44 | host: 'localhost', 45 | macaroon: 'GET FROM CREST', 46 | mode: 'rest', 47 | path: './stores/lightning-playnet/regtest/lightning-rpc', 48 | port: 8181, 49 | secure: false 50 | }, 51 | // Subservices 52 | services: [ 53 | // 'bitcoin', 54 | // 'lightning', 55 | // 'matrix' 56 | ], 57 | upnp: true, 58 | // Log Level 59 | verbosity: 3 // STDOUT 60 | }; 61 | -------------------------------------------------------------------------------- /scripts/playnet.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Bitcoin = require('../services/bitcoin'); 4 | const Environment = require('../types/environment'); 5 | 6 | const environment = new Environment(); 7 | 8 | const INTERVAL = 60000; 9 | const settings = { 10 | seed: environment.readVariable('FABRIC_SEED'), 11 | bitcoin: { 12 | authority: 'http://ahp7iuGhae8mooBahFaYieyaixei6too:naiRe9wo5vieFayohje5aegheenoh4ee@localhost:20444' 13 | } 14 | }; 15 | 16 | async function main (input = {}) { 17 | const bitcoin = new Bitcoin(input.bitcoin); 18 | await bitcoin.start(); 19 | 20 | async function report () { 21 | const height = await bitcoin.getChainHeight(); 22 | const balances = await bitcoin.getBalances(); 23 | console.log('[FABRIC:PLAYNET] Current block height:', height); 24 | console.log('[FABRIC:PLAYNET] Current address:', bitcoin.addresses[0]); 25 | console.log('[FABRIC:PLAYNET] Spendable balance:', balances.trusted); 26 | } 27 | 28 | async function generate () { 29 | const block = await bitcoin.generateBlock(bitcoin.addresses[0].address); 30 | report(); 31 | } 32 | 33 | await report(); 34 | const agent = setInterval(generate, INTERVAL); 35 | return { id: bitcoin.id }; 36 | } 37 | 38 | const safe = Object.assign({}, settings); 39 | safe.seed = '*********************'; 40 | console.log('[FABRIC:PLAYNET] Settings:', safe); 41 | 42 | main(settings).catch((exception) => { 43 | console.error('[FABRIC:PLAYNET] Main Process Exception:', exception); 44 | }).then((output) => { 45 | console.log('[FABRIC:PLAYNET] Main Process Output:', output); 46 | }); 47 | -------------------------------------------------------------------------------- /examples/service.js: -------------------------------------------------------------------------------- 1 | //importScripts('/app.min.js'); 2 | 3 | const url = require('url'); 4 | const Stash = require('../types/stash'); 5 | 6 | self.addEventListener('message', function (e) { 7 | e.source.postMessage('[GUARDIAN]', 'Hello! Your message was: ' + e.data); 8 | }); 9 | 10 | self.addEventListener('fetch', async function (event) { 11 | const self = this; 12 | console.log('[GUARDIAN]', 'request:', event); 13 | 14 | const path = event.request.url; 15 | const target = url.parse(path); 16 | const uri = target.pathname; 17 | 18 | const stash = new Stash(); 19 | console.log('stash:', stash); 20 | console.log('target:', target); 21 | 22 | //await stash.set('/messages', [{ foo: 'bar' }]); 23 | console.log('recovery:', await stash.get('/messages')); 24 | 25 | const value = await stash.get(uri); 26 | if (value) { 27 | console.log('was cached:', uri, value.length, 'bytes'); 28 | const request = new Request(uri, { 29 | // TODO: revert to OPTIONS (this was a temporary fix for an NGINX bug) 30 | method: 'HEAD' 31 | }); 32 | 33 | const response = await fetch(request); 34 | //const content = await response.text(); 35 | return value; 36 | } else { 37 | const request = new Request(uri, { 38 | headers: { 39 | 'X-Identity': 'foo' 40 | } 41 | }); 42 | 43 | const response = await fetch(request); 44 | const content = await response.text(); 45 | console.log('response:', uri, content.length); 46 | 47 | if (content) { 48 | stash.set(uri, content); 49 | } 50 | 51 | return request; 52 | } 53 | }); 54 | -------------------------------------------------------------------------------- /types/capability.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const crypto = require('crypto'); 4 | const m = require('macaroon'); 5 | 6 | const Entity = require('./entity'); 7 | const Signer = require('./signer'); 8 | const Witness = require('./witness'); 9 | 10 | class Capability extends Entity { 11 | constructor (settings = {}) { 12 | super(settings); 13 | 14 | // Initial State 15 | this._state = { 16 | content: { 17 | type: 'Witness' 18 | }, 19 | name: null, 20 | program: [], 21 | witness: null 22 | }; 23 | 24 | this.settings = Object.assign({}, this._state, settings); 25 | this.signer = new Signer(this.settings); 26 | this.witness = new Witness(this.settings); 27 | 28 | return this; 29 | } 30 | 31 | get type () { 32 | return this._state.content.type; 33 | } 34 | 35 | async _generateToken () { 36 | const now = new Date(); 37 | const token = { 38 | created: now.toISOString(), 39 | expiry: now + (60 * 1000), 40 | type: this.type, 41 | version: 2, 42 | rootKey: 'secret', 43 | identifier: 'some id', 44 | location: 'a location' 45 | }; 46 | 47 | const macaroon = m.newMacaroon(token); 48 | 49 | const json = JSON.stringify(token); 50 | const hash = crypto.createHash('sha256').update(Buffer.from(json, 'utf8')).digest('hex'); 51 | const signature = this.signer.sign(Buffer.from(hash, 'hex')); 52 | 53 | return { 54 | json: json, 55 | macaroon: macaroon.exportJSON(), 56 | signature: signature.toString('hex') 57 | }; 58 | } 59 | } 60 | 61 | module.exports = Capability; 62 | -------------------------------------------------------------------------------- /semantic.json: -------------------------------------------------------------------------------- 1 | { 2 | "base": "components/semantic", 3 | "paths": { 4 | "source": { 5 | "config": "src/theme.config", 6 | "definitions": "src/definitions/", 7 | "site": "src/site/", 8 | "themes": "src/themes/" 9 | }, 10 | "output": { 11 | "packaged": "dist/", 12 | "uncompressed": "dist/components/", 13 | "compressed": "dist/components/", 14 | "themes": "assets/themes/" 15 | }, 16 | "clean": "dist/" 17 | }, 18 | "permission": false, 19 | "autoInstall": false, 20 | "rtl": false, 21 | "components": ["reset", "site", "button", "container", "divider", "flag", "header", "icon", "image", "input", "label", "list", "loader", "rail", "reveal", "segment", "step", "breadcrumb", "form", "grid", "menu", "message", "table", "ad", "card", "comment", "feed", "item", "statistic", "accordion", "calendar", "checkbox", "dimmer", "dropdown", "embed", "modal", "nag", "placeholder", "popup", "progress", "slider", "rating", "search", "shape", "sidebar", "sticky", "tab", "text", "toast", "transition", "api", "form", "state", "visibility", "reset", "site", "button", "container", "divider", "emoji", "flag", "header", "icon", "image", "input", "label", "list", "loader", "rail", "reveal", "segment", "step", "breadcrumb", "form", "grid", "menu", "message", "table", "ad", "card", "comment", "feed", "item", "statistic", "accordion", "calendar", "checkbox", "dimmer", "dropdown", "embed", "modal", "nag", "placeholder", "popup", "progress", "slider", "rating", "search", "shape", "sidebar", "sticky", "tab", "text", "toast", "transition", "api", "form", "state", "visibility"], 22 | "version": "2.8.2" 23 | } -------------------------------------------------------------------------------- /types/ledger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Scribe = require('./scribe'); 4 | const Stack = require('./stack'); 5 | 6 | /** 7 | * An ordered stack of pages. 8 | * @property {Buffer} memory The ledger's memory (4096 bytes). 9 | * @property {Stack} stack The ledger's stack. 10 | * @property {Mixed} tip The most recent page in the ledger. 11 | * @extends Scribe 12 | */ 13 | class Ledger extends Scribe { 14 | constructor (state) { 15 | super(state); 16 | 17 | this.memory = Buffer.alloc(4096); 18 | this.pages = new Stack(state || []); 19 | 20 | return this; 21 | } 22 | 23 | get tip () { 24 | return this.pages[this.pages.length - 1]; 25 | } 26 | 27 | async start () { 28 | await super.start(); 29 | 30 | if (!this.pages.length) { 31 | await this.append({ 32 | name: 'genesis' 33 | }); 34 | } 35 | 36 | this.status = 'started'; 37 | 38 | return this; 39 | } 40 | 41 | /** 42 | * Attempts to append a {@link Page} to the ledger. 43 | * @param {Mixed} item Item to store. 44 | * @return {Promise} Resolves after the change has been committed. 45 | */ 46 | async append (item) { 47 | this.pages.push(item); 48 | await this.pages.commit(); 49 | await this.commit(); 50 | return this; 51 | } 52 | 53 | commit () { 54 | if (!this.pages) return null; 55 | this['@data'] = this.pages['@data']; 56 | return this.id; 57 | } 58 | 59 | consume (ink) { 60 | if (!this.ink) this.ink = ink; 61 | return this.ink; 62 | } 63 | 64 | render () { 65 | return ``; 66 | } 67 | } 68 | 69 | module.exports = Ledger; 70 | -------------------------------------------------------------------------------- /types/worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Collection = require('./collection'); 4 | const EncryptedPromise = require('./promise'); 5 | const Entity = require('./entity'); 6 | const Machine = require('./machine'); 7 | const Router = require('./router'); 8 | const Service = require('./service'); 9 | 10 | /** 11 | * Workers are arbitrary containers for processing data. They can be thought of 12 | * almost like "threads", as they run asynchronously over the duration of a 13 | * contract's lifetime as "fulfillment conditions" for its closure. 14 | * @param {Function} method Pure function. 15 | * @constructor 16 | */ 17 | class Worker extends Service { 18 | constructor (method) { 19 | super(method); 20 | // self.worker = new Worker('validator.js'); 21 | this.method = method; 22 | this.machine = new Machine(); 23 | this.router = new Router(); 24 | this.behaviors = {}; 25 | } 26 | 27 | use (definition) { 28 | return this.router.use(definition); 29 | } 30 | 31 | /** 32 | * Handle a task. 33 | * @param {Vector} input Input vector. 34 | * @return {String} Outcome of the requested job. 35 | */ 36 | async compute (input) { 37 | let output = await this.machine.compute(input); 38 | 39 | console.log('[FABRIC:WORKER]', this.machine.clock, 'Computed output:', output); 40 | 41 | switch (input) { 42 | case 'PING': 43 | this.emit('pong'); 44 | break; 45 | } 46 | 47 | return output; 48 | } 49 | 50 | async route (path) { 51 | switch (path) { 52 | default: 53 | await this.compute(path); 54 | break; 55 | } 56 | } 57 | } 58 | 59 | module.exports = Worker; 60 | -------------------------------------------------------------------------------- /examples/cluster/node-a.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SEED = process.env.SEED || 'unknown burger engine plug teach spot squeeze fringe ethics skate riot brand hurry melody double then trumpet impulse lesson inflict enlist eager region ride'; 4 | const PORT = process.env.PORT || 3335; 5 | 6 | // Dependencies 7 | const Peer = require('../../types/peer'); 8 | const Message = require('../../types/message'); 9 | 10 | async function main () { 11 | const peer = new Peer({ 12 | port: PORT, 13 | listen: true, 14 | wallet: { 15 | seed: SEED 16 | } 17 | }); 18 | 19 | // Core functionality (wait for peer, send message) 20 | peer.on('peer:candidate', async function (peer) { 21 | console.log('[EXAMPLES:RELAY]', 'Peer "A" emitted "peer:candidate" event:', peer); 22 | 23 | if (peer.id === PEER_ID) { 24 | console.warn('[EXAMPLES:RELAY]', 'Peer event was destination peer!'); 25 | console.warn('[EXAMPLES:RELAY]', 'Known peers:', peer.peers); 26 | 27 | // Send Message 28 | let message = Message.fromVector(['Generic', 'Hello, world!']); 29 | await peer.broadcast(message); 30 | } 31 | }); 32 | 33 | // Listeners 34 | peer.on('message', async function handleHubMessage (msg) { 35 | console.log('[EXAMPLES:RELAY]', 'Got message on origin:', msg.type, msg.body.toString('utf8')); 36 | }); 37 | 38 | // Start component services 39 | console.warn('[EXAMPLES:RELAY]', 'Starting Peer "A"...'); 40 | await peer.start(); 41 | console.log('[EXAMPLES:RELAY]', 'Peer "A" started!'); 42 | } 43 | 44 | main().catch(function exceptionHandler (exception) { 45 | console.error('[EXAMPLES:RELAY]', 'Main process threw Exception:', exception); 46 | }); -------------------------------------------------------------------------------- /scripts/identity.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { 4 | FIXTURE_SEED 5 | } = require('../constants'); 6 | 7 | const DERIVATION = `m/44'/0'/0'/0/0`; 8 | const PREFIX = 'id'; // 9 | const X_PUBKEY = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'; 10 | 11 | const crypto = require('crypto'); 12 | 13 | // const settings = require('../settings/local'); 14 | const Bech32 = require('../types/bech32'); 15 | const Environment = require('../types/environment'); 16 | const Hash256 = require('../types/hash256'); 17 | const Identity = require('../types/identity'); 18 | const Key = require('../types/key'); 19 | 20 | async function main (input = {}) { 21 | const master = new Key(input); 22 | const child = master.derive(input.derivation); 23 | const pubkeyhash = Hash256.digest(X_PUBKEY); 24 | const truth = crypto.createHash('sha256').update(Buffer.from(X_PUBKEY, 'hex')).digest('hex'); 25 | const obj = Identity.fromString('id163zfyfh2frw4ph7nruu3um7e8qyxw9exs8pahr3wvk4ndlz8lfhq40pmup'); 26 | const identity = new Identity(input); 27 | const frompub = new Identity({ public: X_PUBKEY }); 28 | 29 | const decoded = Bech32.decode(frompub.id); 30 | 31 | return { 32 | id: identity.toString(), 33 | identity: { 34 | pubkey: identity.pubkey 35 | }, 36 | derivation: identity.derivation, 37 | decoded: decoded 38 | }; 39 | } 40 | 41 | main({ 42 | derivation: DERIVATION, 43 | seed: process.env['FABRIC_SEED'] || FIXTURE_SEED 44 | }).catch((exception) => { 45 | console.error('[FABRIC:IDENTITY]', 'Main Process Exception:', exception); 46 | }).then((output) => { 47 | console.log('[FABRIC:IDENTITY]', 'Current Identity:', output); 48 | }); 49 | -------------------------------------------------------------------------------- /types/mempool.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Entity = require('./entity'); 4 | const Service = require('./service'); 5 | const Collection = require('./collection'); 6 | const Transaction = require('./transaction'); 7 | 8 | /** 9 | * Stores a list of {@link Transaction} elements. 10 | * @emits {Message} confirmed Emitted when the Mempool has dropped a transaction. 11 | */ 12 | class Mempool extends Service { 13 | /** 14 | * Creates an instance of a {@link Mempool} {@link Service}. 15 | * @param {Object} settings Map of settings to utilize. 16 | */ 17 | constructor (settings = {}) { 18 | super(settings); 19 | 20 | this.settings = Object.assign({ 21 | name: '@fabric/mempool' 22 | }, settings); 23 | 24 | this.transactions = new Collection({ 25 | type: Transaction 26 | }); 27 | 28 | this._state = { 29 | transactions: [] 30 | } 31 | 32 | return this; 33 | } 34 | 35 | async _remove (txid) { 36 | return false; 37 | } 38 | 39 | async add (transaction) { 40 | const entity = new Entity(transaction); 41 | const target = await this.transactions.create(transaction); 42 | // TODO: compare target.id and entity.id 43 | this._state.transactions.push(entity.id); 44 | } 45 | 46 | async confirm (txid) { 47 | const found = await this._findByTXID(txid); 48 | if (!found) throw new Error(`Could not find transaction: ${txid} in ${JSON.stringify(this.transactions.map())}`); 49 | this.emit('confirmed', txid); 50 | } 51 | 52 | async _findByTXID (txid) { 53 | return this._state.transactions.filter((x) => { 54 | return x.id == query; 55 | }); 56 | } 57 | } 58 | 59 | module.exports = Mempool; 60 | -------------------------------------------------------------------------------- /types/tree.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Dependencies 4 | const merge = require('lodash.merge'); 5 | const { MerkleTree } = require('merkletreejs'); 6 | 7 | // Fabric Types 8 | const Actor = require('./actor'); 9 | const Hash256 = require('./hash256'); 10 | 11 | /** 12 | * Class implementing a Merkle Tree. 13 | */ 14 | class Tree extends Actor { 15 | /** 16 | * Create an instance of a Tree. 17 | * @param {Object} [settings] Configuration. 18 | * @returns {Tree} Instance of the tree. 19 | */ 20 | constructor (settings = {}) { 21 | super(settings); 22 | 23 | if (settings instanceof Array) settings = { leaves: settings }; 24 | 25 | this.settings = merge({ 26 | leaves: [] 27 | }, this.settings, settings); 28 | 29 | this._tree = new MerkleTree(this.settings.leaves, Hash256.digest, { 30 | isBitcoinTree: true 31 | }); 32 | 33 | this._state = { 34 | root: this.root 35 | }; 36 | 37 | return this; 38 | } 39 | 40 | get root () { 41 | return this._tree.getRoot(); 42 | } 43 | 44 | /** 45 | * Add a leaf to the tree. 46 | * @param {String} leaf Leaf to add to the tree. 47 | * @returns {Tree} Instance of the tree. 48 | */ 49 | addLeaf (leaf = '') { 50 | this._tree = new MerkleTree(this.settings.leaves.concat([ 51 | leaf 52 | ]), Hash256.digest, { 53 | isBitcoinTree: true 54 | }); 55 | 56 | this.emit('leaf', leaf); 57 | 58 | return this; 59 | } 60 | 61 | /** 62 | * Get a list of the {@link Tree}'s leaves. 63 | * @returns {Array} A list of the {@link Tree}'s leaves. 64 | */ 65 | getLeaves () { 66 | return this._tree.getLeaves(); 67 | } 68 | } 69 | 70 | module.exports = Tree; 71 | -------------------------------------------------------------------------------- /examples/cluster/node-b.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SEED = process.env.SEED || 'salmon asthma decorate oxygen relief excite lamp huge bunker tennis spread chase liar glass shoe giant crane drama media step crack decline ring stay'; 4 | const PORT = process.env.PORT || 3336; 5 | 6 | // Dependencies 7 | const Peer = require('../../types/peer'); 8 | const Message = require('../../types/message'); 9 | 10 | async function main () { 11 | const peer = new Peer({ 12 | port: PORT, 13 | listen: true, 14 | wallet: { 15 | seed: SEED 16 | }, 17 | peers: ['localhost:3335'] 18 | }); 19 | 20 | // Core functionality (wait for peer, send message) 21 | peer.on('peer:candidate', async function (peer) { 22 | console.log('[EXAMPLES:RELAY]', 'Peer "B" emitted "peer:candidate" event:', peer); 23 | 24 | if (peer.id === PEER_ID) { 25 | console.warn('[EXAMPLES:RELAY]', 'Peer event was destination peer!'); 26 | console.warn('[EXAMPLES:RELAY]', 'Known peers:', peer.peers); 27 | 28 | // Send Message 29 | let message = Message.fromVector(['Generic', 'Hello, world!']); 30 | await peer.broadcast(message); 31 | } 32 | }); 33 | 34 | // Listeners 35 | peer.on('message', async function handleHubMessage (msg) { 36 | console.log('[EXAMPLES:RELAY]', 'Got message on origin:', msg.type, msg.body.toString('utf8')); 37 | }); 38 | 39 | // Start component services 40 | console.warn('[EXAMPLES:RELAY]', 'Starting Peer "B"...'); 41 | await peer.start(); 42 | console.log('[EXAMPLES:RELAY]', 'Peer "B" started!'); 43 | } 44 | 45 | main().catch(function exceptionHandler (exception) { 46 | console.error('[EXAMPLES:RELAY]', 'Main process threw Exception:', exception); 47 | }); -------------------------------------------------------------------------------- /examples/cluster/node-c.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SEED = process.env.SEED || 'frown equal zero tackle relief shallow leisure diet roast festival good plunge pencil virus vote property blame random bacon rich ecology major survey slice'; 4 | const PORT = process.env.PORT || 3337; 5 | 6 | // Dependencies 7 | const Peer = require('../../types/peer'); 8 | const Message = require('../../types/message'); 9 | 10 | async function main () { 11 | const peer = new Peer({ 12 | port: PORT, 13 | listen: true, 14 | wallet: { 15 | seed: SEED 16 | }, 17 | peers: ['localhost:3336'] 18 | }); 19 | 20 | // Core functionality (wait for peer, send message) 21 | peer.on('peer:candidate', async function (peer) { 22 | console.log('[EXAMPLES:RELAY]', 'Peer "C" emitted "peer:candidate" event:', peer); 23 | 24 | if (peer.id === PEER_ID) { 25 | console.warn('[EXAMPLES:RELAY]', 'Peer event was destination peer!'); 26 | console.warn('[EXAMPLES:RELAY]', 'Known peers:', peer.peers); 27 | 28 | // Send Message 29 | let message = Message.fromVector(['Generic', 'Hello, world!']); 30 | await peer.broadcast(message); 31 | } 32 | }); 33 | 34 | // Listeners 35 | peer.on('message', async function handleHubMessage (msg) { 36 | console.log('[EXAMPLES:RELAY]', 'Got message on origin:', msg.type, msg.body.toString('utf8')); 37 | }); 38 | 39 | // Start component services 40 | console.warn('[EXAMPLES:RELAY]', 'Starting Peer "C"...'); 41 | await peer.start(); 42 | console.log('[EXAMPLES:RELAY]', 'Peer "C" started!'); 43 | } 44 | 45 | main().catch(function exceptionHandler (exception) { 46 | console.error('[EXAMPLES:RELAY]', 'Main process threw Exception:', exception); 47 | }); -------------------------------------------------------------------------------- /examples/network.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const playnet = require('../settings/playnet'); 4 | const Peer = require('../types/peer'); 5 | const Message = require('../types/message'); 6 | 7 | const NODE_COUNT = 3; 8 | const PEERING_PORT = 7450; 9 | 10 | /** 11 | * Simulate a Fabric network based on the constants above. 12 | * @return {[type]} [description] 13 | */ 14 | async function simulate () { 15 | const nodes = {}; 16 | const ids = []; 17 | 18 | for (let i = 0; i < NODE_COUNT; i++) { 19 | const node = new Peer({ 20 | listen: true, 21 | port: PEERING_PORT + i // Each peer (after the first) uses port n + 1, 22 | }); 23 | 24 | console.log(`Created node id: ${node.id}`, node.id); 25 | 26 | nodes[node.id] = node; 27 | ids.push(node.id); 28 | } 29 | 30 | console.log('nodes:', nodes); 31 | 32 | for (const id in nodes) { 33 | console.log(`starting ${id}...`); 34 | const node = nodes[id]; 35 | 36 | node.on('ready', function () { 37 | console.log(`node ${id} is ready!`); 38 | const peers = Object.keys(nodes).filter(x => x !== id); 39 | console.log(`node ${id} knows peers:`, peers); 40 | 41 | for (const i in peers) { 42 | const peerID = peers[i]; 43 | const address = `${nodes[peerID].address}:${nodes[peerID].port}`; 44 | console.log(`node ${id} connecting to ${address}...`); 45 | node._connect(address); 46 | } 47 | }); 48 | 49 | nodes[id].listen(); 50 | } 51 | 52 | const origin = nodes[ids[0]]; 53 | const message = Message.fromVector([0x00000012, Date.now() + '']); // ping 54 | 55 | console.log('broadcasting message to all peers:', message); 56 | 57 | origin.broadcast(message); 58 | } 59 | 60 | simulate(); 61 | -------------------------------------------------------------------------------- /types/block.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const merge = require('lodash.merge'); 4 | 5 | const Actor = require('./actor'); 6 | const Transaction = require('./transaction'); 7 | const Tree = require('./tree'); 8 | 9 | class Block extends Actor { 10 | constructor (input = {}) { 11 | super(input); 12 | 13 | this.settings = merge({ 14 | type: 'Block' 15 | }, input); 16 | 17 | this._state = { 18 | parent: null, 19 | transactions: {}, 20 | signatures: [], 21 | content: this.state || input 22 | }; 23 | 24 | Object.defineProperty(this, '_events', { enumerable: false }); 25 | Object.defineProperty(this, '_eventCount', { enumerable: false }); 26 | Object.defineProperty(this, 'observer', { enumerable: false }); 27 | 28 | for (const [id, template] of Object.entries(this.transactions)) { 29 | const tx = new Transaction(template); 30 | if (id !== tx.id) throw new Error(`Transaction hash mismatch! ${id} != ${tx.id}`); 31 | } 32 | 33 | return this; 34 | } 35 | 36 | get tree () { 37 | return new Tree({ 38 | leaves: Object.keys(this.transactions) 39 | }); 40 | } 41 | 42 | get transactions () { 43 | return this._state.transactions; 44 | } 45 | 46 | get transactionIDs () { 47 | return (this.transactions && this.transactions.length) 48 | ? Object.keys(this.transactions) 49 | : []; 50 | } 51 | 52 | sign () { 53 | const actor = new Actor(this._state); 54 | const data = actor.toString(); 55 | const array = this.key._sign(data); 56 | this._state.signature = Buffer.from(array); 57 | return this._state.signature; 58 | } 59 | 60 | validate () { 61 | // TODO: implement validators 62 | } 63 | } 64 | 65 | module.exports = Block; 66 | -------------------------------------------------------------------------------- /BEST_PRACTICES.md: -------------------------------------------------------------------------------- 1 | # Recommendations for Settings, Deploy, and Operation of Fabric-based programs 2 | Complete overview of all agreed-upon recommendations for optimal flow. 3 | 4 | ## Contributing 5 | Contributors should read [`CONTRIBUTING.md`][contributing] in the Fabric root. 6 | 7 | ## Security 8 | ### Git 9 | Git assures we maintain version control over all releases, with our primary 10 | goal being to build Fabric from source and generate a deterministic build. 11 | 12 | **The Recommendations:** 13 | 1. Use Command Line Git. It's self-explanatory. You can do it! 14 | 2. When preparing to share something with your peers, follow these steps: 15 | 0. (Initial Git Install) Ensure [your environment][environment-setup] is setup 16 | 1. Run `git status` to check which files have changed locally 17 | 2. Any files with secret information: `git add -i FILENAME` 18 | 1. Ensure to only add non-private information 19 | 3. Any files you want to share: `git add FILENAME` 20 | 4. Commit to your changes: 21 | 1. Create commit locally: `git commit` 22 | 0. Always use a Capital Letter first, highlight defined terms using Capital Letters, and avoid any punctuating marks 23 | 1. Ensure message contents contains 24 | 1. A brief description of the changes (< 80 characters) 25 | 2. Push to your public share: `git push origin` 26 | 3. (If Upstream Project Exists) `git push upstream` 27 | 5. Click the link in the output of `git push upstream` to acquire SUBMIT_PROPOSAL_HTTP 28 | 6. [Submit a Pull Request][submit-a-pull-request]! 29 | 3. Use [Nix][nix]. 30 | 31 | [contributing]: /CONTRIBUTING.md 32 | [environment-setup]: https://dev.fabric.pub/documents/environment-setup [404] 33 | [nix]: https://nixos.org 34 | [submit-a-pull-request]: https://dev.fabric.pub/documents/submit-a-pull-request [404] 35 | -------------------------------------------------------------------------------- /scripts/example.js: -------------------------------------------------------------------------------- 1 | const util = require('util'); 2 | 3 | const Fabric = require('../lib/fabric'); 4 | const Worker = require('../types/worker'); 5 | 6 | // TODO: generate signature, hash of function definition (the "type") 7 | function Genesis () { 8 | comment = 'Function body is the program.'; 9 | } 10 | 11 | // contract writes to stdout 12 | /** 13 | * Example program. 14 | * @param {Mixed} input Arbitrary input data. 15 | * @constructor 16 | */ 17 | function App (input) { 18 | console.log(`${Date.now()} Called with input: ${JSON.stringify(input, null, ' ')}`); 19 | 20 | // program definition 21 | // these are available to the entire app 22 | function doStuff () { 23 | console.log('leaked data:', this); 24 | let tip = advanceChain(); 25 | return { 26 | tip: tip, 27 | response: 'Did stuff.', 28 | input: input 29 | }; 30 | } 31 | 32 | function advanceChain () { 33 | return { 34 | input: input, 35 | root: root, 36 | seed: Math.random() 37 | }; 38 | } 39 | 40 | let output = doStuff(); 41 | console.log('output:', output); 42 | 43 | advanceChain(); 44 | 45 | return output; 46 | } 47 | 48 | util.inherits(App, Fabric); 49 | 50 | var worker = new Worker(App); 51 | 52 | console.log('worker:', worker); 53 | console.log('method:', worker.method); 54 | console.log('result:', worker.method()); 55 | 56 | // for convenience 57 | function every (list) { 58 | return list.map(App); 59 | } 60 | 61 | function main (input) { 62 | let cores = [Buffer.alloc(32), 'EXAMPLE_STRING', 'input is an array']; 63 | 64 | for (let i = 1; i < 5; i++) { 65 | cores.push({ name: `core-${i}` }) 66 | } 67 | 68 | cores.push(Genesis); 69 | 70 | let many = every(cores); 71 | 72 | console.log('many:', many); 73 | 74 | } 75 | 76 | main(process.stdin); 77 | -------------------------------------------------------------------------------- /tests/fabric.app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const App = require('../types/app'); 4 | 5 | const assert = require('assert'); 6 | const expect = require('chai').expect; 7 | 8 | describe('@fabric/core/types/app', function () { 9 | describe('App', function () { 10 | it('is available from @fabric/core', function () { 11 | assert.equal(App instanceof Function, true); 12 | }); 13 | 14 | xit('should expose a constructor', function () { 15 | assert.equal(typeof App, 'function'); 16 | }); 17 | 18 | it('has a normal lifecycle', async function () { 19 | const app = new App(); 20 | await app.start(); 21 | await app.stop(); 22 | assert.ok(app); 23 | }); 24 | 25 | it('allow a Resource to be defined', async function () { 26 | const app = new App(); 27 | app.define('Example', { 28 | components: { 29 | list: 'fabric-example-list', 30 | view: 'fabric-example-view' 31 | } 32 | }); 33 | 34 | await app.start(); 35 | await app.stop(); 36 | assert.ok(app); 37 | }); 38 | 39 | xit('should create an application smoothly', async function () { 40 | const app = new App(); 41 | await app.start(); 42 | await app.stop(); 43 | assert.ok(app); 44 | }); 45 | 46 | xit('should load data from an oracle', async function () { 47 | const app = new App(); 48 | const oracle = new Oracle({ 49 | path: './data/oracle' 50 | }); 51 | 52 | await app.start(); 53 | await oracle.start(); 54 | 55 | await oracle._load('./resources'); 56 | await app._defer(oracle); 57 | // await app._explore(); 58 | 59 | await app.stop(); 60 | await oracle.stop(); 61 | 62 | assert.ok(oracle); 63 | assert.ok(app); 64 | }); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /assets/fabric.json: -------------------------------------------------------------------------------- 1 | { 2 | "@id": "fb2d32b746ef3dbd71da161fa39587c9a9171cd70b2fb1cc23c9c27fab189986", 3 | "@special~": "JSON notoriously doesn't have comments, so pay attention.", 4 | "@name": "fabric", 5 | "@link": "fabric", 6 | "@type": "Vector", 7 | "@sort": "strict", 8 | "@author": "martindale", 9 | "@comment": "The Vector meta-type is the 'bootstrap' function of the Fabric State Machine (the 'FSM'~ :D). With a valid Vector `v_1` and a shared secret `s'`, we can compute any finite state `v_n`.", 10 | "@genesis": "dev#defines-index", 11 | "@output": "6164376661636232353836666336653936366330303464376431643136623032346635383035666637636234376337613835646162643862343838393263613", 12 | "@contract~?": "@genesis/id", 13 | "@data": { 14 | "peers": [ 15 | "maki.io", 16 | "fabric.fm", 17 | "fabric.pub", 18 | "converse.fm", 19 | "soundtrack.io", 20 | "ericmartindale.com", 21 | "roleplaygateway.com", 22 | "next.maki.io", 23 | "next.fabric.fm", 24 | "next.fabric.pub", 25 | "next.ericmartindale.com", 26 | "next.roleplaygateway.com", 27 | "chat.roleplaygateway.com", 28 | "api.roleplaygateway.com" 29 | ], 30 | "services": { 31 | "http": true, 32 | "tcp": true 33 | }, 34 | "resources": { 35 | "@comment": "Loosely describes a genesis `_lookup`.", 36 | "Index~": "/?id=0#bootstrap" 37 | }, 38 | "expectations": [ 39 | "keys", "assets", 40 | "blocks", "transactions", 41 | "names", "identities", 42 | "components", "resources", "services", "plugins", 43 | "peers", "events", 44 | "sessions" 45 | ], 46 | "plugins": [ 47 | "free" 48 | ] 49 | }, 50 | "root": { 51 | "id": "739c0f6067efff96f6f8f66accc1cf85c9b6cc63e8e0a16f4dead4e471a48b79" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/fabric.hash256.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Hash256 = require('../types/hash256'); 5 | 6 | const sample = 'Hello, world!'; 7 | const fixture = '315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3'; 8 | 9 | describe('@fabric/core/types/hash256', function () { 10 | describe('Hash256', function () { 11 | it('is available from @fabric/core', function () { 12 | assert.strictEqual(Hash256 instanceof Function, true); 13 | }); 14 | 15 | it('can instantiate with no data', function () { 16 | const hash256 = new Hash256(); 17 | assert.ok(hash256); 18 | assert.ok(hash256.value); 19 | assert.strictEqual(hash256.value.length, 64); 20 | }); 21 | 22 | it('can instantiate from sample data', function () { 23 | const hash256 = new Hash256(sample); 24 | assert.ok(hash256); 25 | assert.ok(hash256.value); 26 | assert.strictEqual(hash256.value.length, 64); 27 | assert.strictEqual(hash256.value, fixture); 28 | }); 29 | 30 | it('provides a static digest() method', function () { 31 | const digest = Hash256.digest(sample); 32 | assert.ok(digest); 33 | assert.strictEqual(digest.length, 64); 34 | assert.strictEqual(digest, fixture); 35 | }); 36 | 37 | it('throws an error when static digest() is called on a non-string', function () { 38 | assert.throws(() => Hash256.digest({ sample })); 39 | }); 40 | 41 | it('can reverse a known hash', function () { 42 | assert.throws(() => Hash256.digest({ sample })); 43 | 44 | const digest = Hash256.digest(sample); 45 | const reversed = (new Hash256(sample)).reverse(); 46 | 47 | assert.strictEqual(digest, fixture); 48 | assert.strictEqual(reversed, 'd3ed9458c794fc5b3469c877ce1f2b6164014a4e06c08a3bc478d076db5b5f31'); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /tests/fabric.router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const Router = require('../types/router'); 5 | 6 | // TODO: test class/function middleware 7 | const middleware = { 8 | name: 'example', 9 | value: 'Hello, world.' 10 | }; 11 | 12 | const message = { 13 | actor: 'Tester', 14 | object: 'Some !example especially for this.', 15 | target: '/messages' 16 | }; 17 | 18 | describe('@fabric/core/types/router', function () { 19 | describe('Router', function () { 20 | it('is available from @fabric/core', function () { 21 | assert.equal(Router instanceof Function, true); 22 | }); 23 | 24 | it('can start and stop cleanly', async function () { 25 | async function test () { 26 | const router = new Router(); 27 | await router.start(); 28 | await router.stop(); 29 | assert.ok(router); 30 | } 31 | 32 | await test(); 33 | }); 34 | 35 | it('can use a middleware', async function () { 36 | async function test () { 37 | const router = new Router(); 38 | router.use(middleware); 39 | 40 | await router.start(); 41 | await router.stop(); 42 | 43 | assert.ok(router); 44 | } 45 | 46 | await test(); 47 | }); 48 | 49 | it('can route a message', async function () { 50 | async function test () { 51 | const router = new Router(); 52 | let response = null; 53 | router.use(middleware); 54 | 55 | await router.start(); 56 | 57 | try { 58 | response = await router.route(message); 59 | } catch (exception) { 60 | assert.fail('Routing failed:', exception); 61 | } 62 | 63 | await router.stop(); 64 | 65 | assert.ok(router); 66 | assert.ok(response); 67 | } 68 | 69 | await test(); 70 | }); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /examples/heartbeat.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Dependencies 4 | const Peer = require('../types/peer'); 5 | const Swarm = require('../types/swarm'); 6 | const Message = require('../types/message'); 7 | 8 | // Configuration 9 | const settings = { 10 | seeds: ['localhost:7777'] 11 | }; 12 | 13 | async function main () { 14 | // Create a Hub (seeder peer) and a Swarm (peer cluster) 15 | let seeder = new Peer({ listen: true }); 16 | let swarm = new Swarm(settings); 17 | 18 | // Listeners 19 | seeder.on('message', async function handleHubMessage (msg) { 20 | console.log('[EXAMPLES:HEARTBEAT]', 'Got message on Seed node:', msg.raw); 21 | }); 22 | 23 | swarm.on('message', async function handleSwarmMessage (msg) { 24 | console.log('[EXAMPLES:HEARTBEAT]', 'Got message on Swarm:', msg.raw); 25 | }); 26 | 27 | // Start component services 28 | console.log('[EXAMPLES:HEARTBEAT]', 'Starting seeder Peer...'); 29 | await seeder.start(); 30 | console.log('[EXAMPLES:HEARTBEAT]', 'Seeder peer started!'); 31 | 32 | console.log('[EXAMPLES:HEARTBEAT]', 'Starting Swarm...'); 33 | await swarm.start(); 34 | console.log('[EXAMPLES:HEARTBEAT]', 'Swarm started!'); 35 | 36 | // Send Regular Updates (outside of internal ping/pong) 37 | const heartbeat = setInterval(function () { 38 | console.warn('[EXAMPLES:HEARTBEAT]', 'Starting to send interval message...'); 39 | const message = Message.fromVector(['Generic', Date.now().toString()]); 40 | console.log('[EXAMPLES:HEARTBEAT]', 'Sending :', message.raw); 41 | 42 | // Send interval message through seed node 43 | seeder.broadcast(message); 44 | 45 | // Send interval message through swarm agent 46 | // swarm.broadcast(message); 47 | }, 5000); 48 | } 49 | 50 | main().catch(function exceptionHandler (exception) { 51 | console.error('[EXAMPLES:HEARTBEAT]', 'Main process threw Exception:', exception); 52 | }); -------------------------------------------------------------------------------- /contracts/figure-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | Simple 11 | 12 | Figure 1: A Simple Program 13 | 14 | cluster_variables 15 | 16 | Δ 17 | 18 | 19 | 20 | input 21 | 22 | input 23 | 24 | 25 | 26 | output 27 | 28 | output 29 | 30 | 31 | 32 | input->output 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /types/stash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // TODO: note that generally, requirements are loosely ordered by 3 | // their relative importance to the file in question 4 | const util = require('util'); 5 | const localforage = require('localforage'); 6 | 7 | function Stash (vector) { 8 | this.config = Object.assign({ 9 | path: './stores/store', 10 | get: this.get, 11 | set: this.set, 12 | del: this.del, 13 | transform: this.transform, 14 | createReadStream: this.createReadStream 15 | }, vector || {}); 16 | 17 | this.clock = 0; 18 | this.stack = []; 19 | this.known = {}; 20 | 21 | this.open(); 22 | 23 | this.init(); 24 | } 25 | 26 | util.inherits(Stash, require('./vector')); 27 | 28 | Stash.prototype.open = function load () { 29 | this.db = localforage.createInstance({ 30 | name: 'fabric' 31 | }); 32 | }; 33 | 34 | Stash.prototype.get = async function GET (key) { 35 | var self = this; 36 | var value = await self.db.getItem(key); 37 | if (!value) return null; 38 | // if (typeof value !== 'string') return JSON.parse(value); 39 | return value; 40 | }; 41 | 42 | Stash.prototype.set = async function PUT (key, value) { 43 | var self = this; 44 | if (typeof value !== 'string') { 45 | value = self._serialize(value); 46 | } 47 | 48 | await self.db.setItem(key, value); 49 | 50 | return await self.db.getItem(key); 51 | }; 52 | 53 | Stash.prototype.del = async function DEL (key) { 54 | return await this.db.setItem(key, null); 55 | }; 56 | 57 | Stash.prototype.transform = function TRANSFORM (transaction, done) { 58 | // this.db.del(batch, done); 59 | return new Error('not yet implemented'); 60 | }; 61 | 62 | Stash.prototype.createReadStream = function createReadStream () { 63 | return this.db.createReadStream(); 64 | }; 65 | 66 | Stash.prototype.close = async function close () { 67 | return await this.db.close(); 68 | }; 69 | 70 | module.exports = Stash; 71 | -------------------------------------------------------------------------------- /IDENTITY.md: -------------------------------------------------------------------------------- 1 | # Fabric Identity 2 | This document is intended to be utilized as the specification for the Fabric Identity Protocol. 3 | 4 | ## Overview 5 | The Fabric Identity Protocol is a decentralized identifier for Fabric-speaking networks. 6 | 7 | 1. Load a BIP44 HD tree 8 | 2. Designate First Identity as Derivation Path: `m/44'/7778'/0'/0/0` 9 | 3. `m = sha256(derived_pubkey)` 10 | 4. `id = bech32m("id", m) // "id" taken as ASCII bytes` 11 | 12 | Additional identities may be loaded by modifying the account index in the derivation path: 13 | 14 | ``` 15 | Identity #1 [0]: m/44'/7778'/0'/0/0 16 | Identity #2 [1]: m/44'/7778'/1'/0/0 17 | ... 18 | ``` 19 | 20 | Fabric will encode each transaction using the address index field, as specified in BIP 44: 21 | 22 | ``` 23 | Transaction #1 [1]: m/44'/7778'/0'/1/0 24 | ``` 25 | 26 | ### Full Specification 27 | `id = bech32m("id", sha256(bip44(derivation_path, hd_tree).public))` 28 | 29 | ### An Example Fabric Identity: 30 | ``` 31 | Pubkey: 32 | ID: 33 | ``` 34 | 35 | ### HTTP Requests 36 | Send authenticated HTTP requests with the following headers: 37 | 38 | ``` 39 | X-Fabric-Identity: # should be in form id 40 | X-Fabric-ECDSA: 41 | X-Fabric-Signature: where m = HTTP Request Body (utf8) 42 | ``` 43 | 44 | ## Bridging 45 | Identities from external networks can be "attested" to within Fabric. 46 | 47 | ### Labels 48 | For example, Discord users may run the `!fabric assert ` command in any room [an attestation bot][attestation-bot] is present: 49 | 50 | ``` 51 | martindale: !fabric assert 52 | ExampleBot: Please run `fabric prove feebadee` and provide the output signature to the command: `!fabric prove ` 53 | martindale: !fabric prove feba3b56b1ebadb3b691b124bb3 54 | ExampleBot: Your Discord identity has been confirmed! 55 | ``` 56 | 57 | [attestation-bot]: https://github.com/FabricLabs/fabric-discord 58 | -------------------------------------------------------------------------------- /tests/fabric.stack.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fabric = require('../'); 4 | 5 | const assert = require('assert'); 6 | const expect = require('chai').expect; 7 | 8 | describe('@fabric/core/types/stack', function () { 9 | describe('Stack', function () { 10 | it('is available from @fabric/core', function () { 11 | assert.equal(Fabric.Stack instanceof Function, true); 12 | }); 13 | 14 | it('can restore state from an Array-like object', function () { 15 | let stack = new Fabric.Stack(['test']); 16 | // console.log('stack:', stack); 17 | // console.log('stack.render():', stack.render()); 18 | 19 | // TODO: move to constants, verify 20 | assert.equal(stack.id, 'a5b08f19adfd2918e354af8c11e1b4efd963b5f5a525900d63a01cd2fd28176f'); 21 | }); 22 | 23 | xit('can instantiate from a serialized state', function () { 24 | // TODO: migrate to Stack 25 | let stack = Fabric.Vector.fromObjectString('{ "0": { "type": "Buffer", "data": [0, 0, 0, 0 ] } }'); 26 | assert.equal(stack instanceof Array, true); 27 | assert.equal(stack[0] instanceof Buffer, true); 28 | assert.equal(stack[0].toString('hex'), '00000000'); 29 | assert.ok(stack); 30 | }); 31 | 32 | xit('can push an element onto the stack', function () { 33 | let stack = new Fabric.Stack(); 34 | 35 | let one = stack.push('foo'); 36 | let two = stack.push('bar'); 37 | 38 | assert.equal(one, 1); 39 | assert.equal(two, 2); 40 | assert.equal(stack['@data'][0].toString('hex'), samples.output.foo); 41 | assert.equal(stack['@data'][1].toString('hex'), samples.output.bar); 42 | }); 43 | 44 | xit('mimics JavaScript semantics', function () { 45 | let stack = new Fabric.Stack(); 46 | 47 | stack.push('foo'); 48 | stack.push('bar'); 49 | 50 | let last = stack.pop(); 51 | 52 | assert.equal(last, 'bar'); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /examples/game.js: -------------------------------------------------------------------------------- 1 | const _ = require('../contracts/functions'); 2 | 3 | const Fabric = require('../types/fabric'); 4 | const game = new Fabric({ 5 | spawns: [] 6 | }); 7 | 8 | const template = require('../data/mob'); 9 | 10 | game.use('tick', function (input) { 11 | const self = this; 12 | console.log('tick!', self.clock); 13 | return input; 14 | }); 15 | 16 | game.use('spawn', function (input) { 17 | var self = this; 18 | var data = _.clone(template); 19 | 20 | data.id = Math.random(); 21 | 22 | var mob = new Fabric(data); 23 | 24 | mob.use('attack', function (target, stack) { 25 | console.log('attack!', target); 26 | console.log('attack stack:', stack); 27 | 28 | mob.broadcast('attack', '/spawns/1'); 29 | 30 | /*var tx = new Transaction({ 31 | 32 | });*/ 33 | 34 | //target.transactions.push(tx); 35 | //target.transactions.push(tx); 36 | 37 | // TODO: use fabric call 38 | //input.spawns[1].life -= 5; 39 | 40 | return target; 41 | }); 42 | 43 | mob.on('attack', function (target) { 44 | console.log('mob attack:', target); 45 | game.patch([ 46 | { op: 'replace', path: target + '/life', value: 0 } 47 | ]); 48 | //game.compute(); 49 | }); 50 | 51 | mob.compute(); 52 | 53 | input.spawns.push(mob); 54 | 55 | return input; 56 | }); 57 | 58 | game.use('battle', function (input) { 59 | var self = this; 60 | 61 | console.log('battling...', input.spawns); 62 | 63 | input.spawns[0].stack.push('attack'); 64 | input.spawns[0].compute(); 65 | 66 | return input; 67 | }); 68 | 69 | game.stack.push('spawn'); 70 | game.stack.push('spawn'); 71 | //game.stack.push('spawn'); 72 | game.stack.push('battle'); 73 | 74 | game.on('mutation', function(i) { 75 | console.log('m:', i.map(function(x) { 76 | return x.path; 77 | })); 78 | }); 79 | 80 | game.compute(); 81 | 82 | console.log('world:', game['@data'].spawns.map(function(x) { 83 | return x; 84 | })); 85 | -------------------------------------------------------------------------------- /contracts/exchange.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Settings 4 | // const defaults = require('../settings/default'); 5 | const playnet = require('../settings/playnet'); 6 | 7 | const settings = { 8 | debug: true, 9 | upnp: false, 10 | listen: true, 11 | persistent: false, // Loads from anchor chain 12 | // sideload playnet 13 | // peers: [].concat(playnet.peers), 14 | peers: [], 15 | services: [ 16 | 'exchange', 17 | 'lightning' 18 | ], 19 | key: { 20 | seed: playnet.seed 21 | }, 22 | anchor: 'BTC', 23 | bitcoin: false, // disable Bitcoin (for now) 24 | currencies: [].concat(playnet.currencies), 25 | orders: [] 26 | }; 27 | 28 | // Fabric Types 29 | const CLI = require('../types/cli'); 30 | 31 | // Services 32 | const Bitcoin = require('../services/bitcoin'); 33 | // const Ethereum = require('../services/ethereum'); 34 | // const Exchange = require('../services/exchange'); 35 | const Lightning = require('../services/lightning'); 36 | 37 | // Program Definition 38 | async function OP_EXCHANGE () { 39 | // Configure Earning 40 | if (this.earn) { 41 | console.log('[!!] earning enabled [!!!]'); 42 | console.log('This node will attempt to bid on live contracts. Beware of'); 43 | console.log('the consequences of your actions!'); 44 | } 45 | 46 | if (this.seed) { 47 | settings.key.seed = this.seed; 48 | } else if (process.env.FABRIC_SEED) { 49 | settings.key.seed = this.seed; 50 | } 51 | 52 | // Fabric CLI 53 | const exchange = new CLI(settings); 54 | 55 | // ## Services 56 | // TODO: reconcile API wth @fabric/doorman as appears at: https://github.com/FabricLabs/doorman 57 | // exchange._registerService('exchange', Exchange); 58 | // exchange._registerService('eth', Ethereum); 59 | // exchange._registerService('lightning', Lightning); 60 | 61 | await exchange.start(); 62 | 63 | // Resolves to 0 or 64 | return exchange.fingerprint(); 65 | } 66 | 67 | // Module 68 | module.exports = OP_EXCHANGE; 69 | -------------------------------------------------------------------------------- /types/codec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Dependencies 4 | const merge = require('lodash.merge'); 5 | 6 | // Fabric Types 7 | const Label = require('./label'); 8 | const Key = require('./key'); 9 | const Actor = require('./actor'); 10 | 11 | class Codec { 12 | constructor (settings = {}) { 13 | this.settings = merge({ 14 | type: 'FabricCodec', 15 | version: 0, 16 | key: { 17 | seed: null, 18 | private: null, 19 | public: null 20 | }, 21 | buffer: true 22 | }, this.settings, settings); 23 | 24 | this.key = new Key(this.settings.key); 25 | this._state = { 26 | actors: {}, 27 | labels: {} 28 | }; 29 | 30 | return this; 31 | } 32 | 33 | get type () { 34 | return this.settings.type; 35 | } 36 | 37 | get buffer () { 38 | return this.settings.buffer; 39 | } 40 | 41 | _registerActor (actor) { 42 | this._state.actors[actor.id] = actor; 43 | return this._state.actors[actor.id]; 44 | } 45 | 46 | _registerLabel (label) { 47 | this._state.labels[label._id] = label; 48 | return this._state.labels[label._id]; 49 | } 50 | 51 | encode (data) { 52 | if (typeof data !== 'string') data = JSON.stringify(data); 53 | try { 54 | const actor = new Actor(data); 55 | const label = new Label(`${this.key.pubkey}/${actor.id}`); 56 | const blob = this.key.encrypt(data); 57 | this._registerActor(actor); 58 | this._registerLabel(label); 59 | return blob; 60 | } catch (exception) { 61 | console.error('err:', exception); 62 | } 63 | } 64 | 65 | decode (blob) { 66 | try { 67 | const actor = new Actor(blob); 68 | const label = new Label(`${this.key.pubkey}/${actor.id}`); 69 | const data = this.key.decrypt(blob); 70 | this._registerActor(actor); 71 | this._registerLabel(label); 72 | return data; 73 | } catch (exception) { 74 | console.error('err:', exception); 75 | } 76 | } 77 | } 78 | 79 | module.exports = Codec; 80 | -------------------------------------------------------------------------------- /snippets/sidechains.md: -------------------------------------------------------------------------------- 1 | # Sidechains 2 | In contrast to an **anchor chain**, a **sidechain** is only shared between a set of mutually-interested peers. 3 | 4 | ## Bitcoin Sidechains 5 | ### Example 6 | 1. Bitcoin mainchain (the "anchor chain") 7 | 2. Fabric sidechain (Alice, Bob, and Carol) 8 | 9 | #### Example Flow 10 | 1. Alice transfers 1 BTC to the sidechain (the **"peg-in"**), crediting 1 BTC (the mainchain asset) and debiting 1 F-BTC (the sidechain asset) 11 | 2. Alice transfers 0.2 F-BTC to Bob, creating a **sidechain transaction** with herself receiving 0.8 F-BTC and Bob receiving 0.2 F-BTC 12 | 3. Alice, Bob, and Carol gossip the **sidechain transaction**, validate it, and create a **sidechain block** 13 | 4. Bob now controls 0.2 F-BTC, and redeems it on the mainchain (the **"peg-out"**) for 0.2 BTC (the **anchor asset**) 14 | 5. Alice may continue transacting with her 0.8 F-BTC or redeem it back for 0.8 BTC 15 | 16 | ## The Elements Project 17 | To reduce complexity in sidechain implementations, [the Elements Project][elements-project] is forked from the Bitcoin Core source code — thereby retaining the same APIs as Bitcoin itself, but adding any new features or functionality as new RPC methods. 18 | 19 | ## Fabric Statechains 20 | Fabric utilizes sidechains in the form of **Statechains**, which enable proof-by-execution modification of a shared, mutual state validated against rules pre-determined by the initial contract. 21 | 22 | ### Bond Phase 23 | An initial bond is offered, typically at an `n:1` ratio where `n` is the number of contract counterparties. 24 | 25 | ### Negotiation Phase 26 | Contract proposals are shared between peers until an `n of n` agreement is reached. 27 | 28 | ### Execution Phase 29 | Transactions are made which modify contract state along the terms of the unanimously-agreed contract. 30 | 31 | ### Closure Phase 32 | The contract is complete, and all parties are in possession of the final state, enabling unlock and spending on the anchor chain. 33 | 34 | [elements-project]: https://elementsproject.org 35 | -------------------------------------------------------------------------------- /types/consensus.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // For browsers... 4 | // const bcoin = require('bcoin/lib/bcoin-browser'); 5 | // const bcash = require('bcash/lib/bcoin-browser'); 6 | 7 | // For node... 8 | const bcoin = require('bcoin'); 9 | 10 | /** 11 | * Provides various network-specific rules. 12 | */ 13 | class Consensus { 14 | /** 15 | * Create an instance of a {@link Consensus} verifier. 16 | * @param {Object} [settings] Configuration for the network. 17 | * @param {String} [settings.network] Name of the network. 18 | * @param {String} [settings.provider] Name of the source provider. 19 | */ 20 | constructor (settings = {}) { 21 | this.settings = Object.assign({ 22 | network: 'mainnet', 23 | provider: 'bcoin' 24 | }, settings); 25 | 26 | // TODO: define class ConsensusProvider 27 | this.providers = { bcoin }; 28 | } 29 | 30 | get SEQUENCE_GRANULARITY () { 31 | return this.providers[this.settings.provider].SEQUENCE_GRANULARITY; 32 | } 33 | 34 | get SEQUENCE_MASK () { 35 | return this.providers[this.settings.provider].SEQUENCE_MASK; 36 | } 37 | 38 | get SEQUENCE_TYPE_FLAG () { 39 | return this.providers[this.settings.provider].SEQUENCE_TYPE_FLAG; 40 | } 41 | 42 | get Block () { 43 | return this.providers[this.settings.provider].Block; 44 | } 45 | 46 | get FullNode () { 47 | return this.providers[this.settings.provider].FullNode; 48 | } 49 | 50 | get MTX () { 51 | return this.providers[this.settings.provider].MTX; 52 | } 53 | 54 | get Script () { 55 | return this.providers[this.settings.provider].Script; 56 | } 57 | 58 | get Transaction () { 59 | return this.providers[this.settings.provider].Transaction; 60 | } 61 | 62 | // TODO: remove from {@link Consensus} 63 | get Wallet () { 64 | return this.providers[this.settings.provider].Wallet; 65 | } 66 | 67 | get blocks () { 68 | return { 69 | // TODO: compute from chain height 70 | subsidy: 50 71 | } 72 | } 73 | 74 | get port () { 75 | return (this.settings.provider === 'bcash') ? 18033 : 18332; 76 | } 77 | } 78 | 79 | module.exports = Consensus; 80 | -------------------------------------------------------------------------------- /docs/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | --------------------------------------------------------------------------------