1
0
mirror of https://github.com/bigchaindb/site.git synced 2024-11-22 01:36:55 +01:00

Merge pull request #189 from ascribe/feature/guides

Guides section
This commit is contained in:
Matthias Kretschmann 2018-02-21 12:37:35 +01:00 committed by GitHub
commit 0099c98787
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1809 additions and 376 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ yarn.lock
.bundle
vendor/
package-lock.json
*.code-workspace

View File

@ -4,6 +4,7 @@ group :jekyll do
gem 'jekyll'
gem 'jekyll-sitemap'
gem 'jekyll-redirect-from'
gem 'jekyll-toc'
gem 'redcarpet'
end

View File

@ -90,13 +90,25 @@ collections:
partners:
output: true
permalink: /:collection/:path/
guides:
output: true
permalink: /:collection/:path/
defaults:
- scope:
path: ""
type: guides
values:
toc: true
image: share-image-guides.png
js: page-guides.min.js
# Plugins
# --------------------
plugins:
- jekyll-sitemap
- jekyll-redirect-from
- jekyll-toc
jekyll_get:

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@ -23,7 +23,7 @@ jQuery(function($) {
//
// init Smooth Scroll
//
var scroll = new SmoothScroll('a[data-scroll]', {
var scroll = new SmoothScroll('a[data-scroll], .toc-entry a', {
easing: 'easeOutQuint'
});

View File

@ -0,0 +1,32 @@
//=include clipboard/dist/clipboard.js
document.addEventListener('DOMContentLoaded', (event) => {
// Clipboard button
const clipboardImage = '<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22"><path d="M16 8v8H8v4h12V8h-4zm0-2h6v16H6v-6H0V0h16v6zM2 2v12h12V2H2z"></path></svg>'
const successImage = '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><path d="M2.12132034,39.4786797 C0.949747468,38.3071068 -0.949747468,38.3071068 -2.12132034,39.4786797 C-3.29289322,40.6502525 -3.29289322,42.5497475 -2.12132034,43.7213203 L14.2786797,60.1213203 C15.5878487,61.4304894 17.7587151,61.2529588 18.8377878,59.7484823 L60.4377878,1.74848232 C61.403448,0.402129267 61.0948354,-1.47212773 59.7484823,-2.43778785 C58.4021293,-3.40344797 56.5278723,-3.09483537 55.5622122,-1.74848232 L16.0221415,53.3795008 L2.12132034,39.4786797 Z" transform="translate(3 3)"/></svg>'
const clipboardButton = `<button class="btn btn--clipboard" title="Copy to clipboard">${clipboardImage}</button>`
const codeBlocks = document.querySelectorAll('.highlight')
codeBlocks.forEach(codeBlock => {
codeBlock.insertAdjacentHTML('afterbegin', clipboardButton)
})
const buttons = document.querySelectorAll('.highlight .btn--clipboard')
buttons.forEach(button => {
const clipboard = new Clipboard(button, {
target: (trigger) => {
return trigger.nextElementSibling;
}
})
clipboard.on('success', e => {
e.trigger.classList.add('success')
e.trigger.innerHTML = successImage
e.trigger.insertAdjacentHTML('afterend', '<span class="success__text">Copied to clipboard</span>')
e.clearSelection()
})
})
})

View File

@ -5,7 +5,8 @@
//
.page-front {
.section--partners,
.section--guides,
.section--blog,
.section-testimonials {
@extend .background--darker;
}

View File

@ -0,0 +1,237 @@
.header--guides {
background: url('../img/nosprite/starbase-guides.svg') no-repeat center bottom;
background-size: contain;
padding-bottom: 18%;
&:before {
display: none;
}
> .row {
@extend .row--wide;
}
.header__content {
padding-top: ($spacer * 5);
padding-bottom: ($spacer * 5);
}
.header__tagline {
@media ($screen-sm) {
max-width: 40rem;
margin-left: auto;
margin-right: auto;
}
}
}
.header--guide {
.header__content {
padding-top: ($spacer * 5);
padding-bottom: ($spacer * 5);
}
}
.content--guide {
.content--page--markdown {
padding-top: $spacer * 4;
h1,
h2,
h3,
h4 {
font-weight: $font-weight-normal;
}
h2,
h3,
h4 {
text-align: left;
border: 0;
padding: 0;
}
h1 {
font-size: $font-size-h3;
}
h2 {
font-size: $font-size-h4;
margin-top: ($spacer * 2.5);
}
h3 {
font-size: $font-size-base;
font-weight: $font-weight-normal;
color: #fff;
margin-bottom: $spacer;
margin-top: ($spacer * 2);
}
}
}
.section-header--guide {
margin-bottom: $spacer * 3;
.section-description {
text-align: left;
h2 {
@extend .h5;
margin-top: 0;
font-size: $font-size-lg;
}
ul {
margin: 0;
}
}
}
.section--guides-more {
padding-top: 0;
}
.guide {
height: 100%;
a {
@include color-overlay;
background-size: cover;
background-position: center;
background-image: url('../img/hero-berlin.jpg');
display: block;
box-shadow: none;
background-color: $brand-main-blue-dark;
padding: $spacer * 1.5;
height: 100%;
border-radius: $border-radius;
@media ($screen-sm) {
padding: $spacer * 3;
}
&:before {
opacity: .85;
}
&:hover,
&:focus {
background-size: cover;
background-position: center;
box-shadow: 0 2px 5px rgba($brand-main-blue-dark, .2);
transform: translateY(-1px);
}
}
p:last-child,
.guide__title:only-child,
.guide__tagline,
.grid {
margin-bottom: 0;
}
.section--guides &,
.section--guideslist & {
margin-bottom: $spacer * 2;
a {
@media ($screen-sm) {
padding: $spacer * 4;
}
}
}
}
.guide__title,
.guide__tagline {
position: relative;
z-index: 1;
}
.guide__title,
h1.guide__title {
font-size: $font-size-h4;
font-weight: $font-weight-normal;
margin-bottom: $spacer / $line-height;
margin-top: 0;
color: #fff;
}
.guide__tagline {
color: $brand-main-blue-light;
}
//
// TOC
//
.section-nav {
background: darken($brand-main-gray, 2%);
margin-top: 0;
margin-bottom: $spacer * 2;
padding: $spacer * 1.5;
padding-bottom: $spacer * 2;
border-radius: $border-radius;
a {
&:hover,
&:focus {
color: #fff;
}
}
}
li.toc-h1 {
// custom numbers
&:before {
font-size: $font-size-base;
opacity: .6;
color: $brand-main-blue-light;
}
a {
font-size: $font-size-base;
margin: 0;
box-shadow: none;
color: $brand-main-blue-light;
}
ul {
padding-left: $spacer * 2.6;
}
}
li.toc-h2 {
a {
font-size: $font-size-sm;
color: $text-color;
}
}
li.toc-h3 {
display: none;
}
.section--getstarted {
padding-bottom: 0;
.section-header {
margin-bottom: -($spacer * 3.5);
position: relative;
z-index: 10;
.btn {
margin-top: $spacer * 2;
}
}
}
.image--create-transfer {
max-width: calc(100% + 1rem) !important; //stylelint-disable-line declaration-no-important
margin-left: -1rem;
@media ($screen-sm) {
max-width: calc(100% + 1.5rem) !important; //stylelint-disable-line declaration-no-important
margin-left: -1.5rem;
}
}

View File

@ -20,8 +20,10 @@
}
}
.article__title {
@extend .h6, .transition;
.article__title,
h1.article__title {
font-size: $font-size-h5;
font-weight: $font-weight-normal;
margin: 0;
color: #fff;
position: relative;

View File

@ -63,3 +63,4 @@
@import 'page-enterprise';
@import 'page-faq';
@import 'oceanprotocol';
@import 'page-guides';

View File

@ -8,13 +8,13 @@ kbd,
pre,
samp {
font-family: $font-family-monospace;
font-size: .75rem;
font-size: .7em; // use em so inline code can be used withing large and small modifiers
hyphens: none;
}
// Inline code
code {
padding: 2px 4px;
padding: .1rem .3rem;
color: $code-color;
background-color: $code-bg;
border-radius: $border-radius;
@ -22,7 +22,7 @@ code {
// User input typically entered via keyboard
kbd {
padding: 2px 4px;
padding: .1rem .3rem;
color: $kbd-color;
background-color: $kbd-bg;
border-radius: $border-radius-sm;
@ -39,7 +39,7 @@ kbd {
// Blocks of code
pre {
display: block;
padding: 1em;
padding: $spacer / 1.5;
margin: 0 0 $spacer;
line-height: $line-height;
word-break: break-all;
@ -67,3 +67,47 @@ pre {
border-radius: 0;
}
}
//
// Clipboard button
//
.highlight {
position: relative;
.btn--clipboard,
.success__text {
position: absolute;
top: .1rem;
right: .1rem;
}
.success__text {
top: 2rem;
right: -1.5rem;
font-size: $font-size-xs;
}
}
.btn--clipboard {
padding: 0 $spacer / 2;
box-shadow: none;
background: $brand-main-gray;
color: $brand-main-gray-light;
outline: 0;
svg {
fill: currentColor;
width: $font-size-sm;
height: $font-size-sm;
}
&:hover,
&:focus {
transform: none;
background: lighten($brand-main-gray, 5%);
}
&.success {
background: $brand-success;
}
}

View File

@ -10,12 +10,11 @@
> h1,
h2,
.faq__question {
&:not(#heading-1):not(#heading-2) {
border-bottom: 1px solid $brand-main-blue-light;
padding-bottom: $spacer;
margin-bottom: ($spacer * 2);
text-align: center;
}
border-bottom: 2px solid $brand-main-blue-light;
padding-bottom: $spacer;
margin-bottom: ($spacer * 1.5);
margin-top: ($spacer * 3);
position: relative;
&:hover {
.header-link {
@ -28,10 +27,13 @@
.header-link {
box-shadow: none;
transition-timing-function: $timing-bounce;
display: inline-block;
display: block;
padding: 0 .25rem;
opacity: 0;
transform: translate3d(20px, 0, 0) scale(0);
position: absolute;
left: -1.15rem;
top: 0;
&,
.header-icon {

View File

@ -1,18 +1,17 @@
.header {
@extend .background--photo;
background-image: url('../img/header-berlin.jpg');
background-position: center bottom;
background-position: center center;
}
.header__content {
padding: ($spacer * 3) 0;
padding: ($spacer * 4) 0;
text-align: center;
}
// intro animation
.header__title,
.header__tagline,
.header__description,
.header__logo,
.header__label {
.wf-active &,
@ -22,7 +21,7 @@
}
}
.header__description,
.header__tagline,
.header__logo {
.wf-active &,
.wf-inactive & {
@ -46,7 +45,9 @@
margin: 0;
}
.header__tagline {
font-size: $font-size-h3;
color: #fff;
.header__tagline,
h2.header__tagline {
font-size: $font-size-h4;
font-weight: $font-weight-normal;
margin-top: $spacer;
}

View File

@ -3,7 +3,8 @@ figure {
margin: 0;
}
.img--responsive {
.img--responsive,
.content--page--markdown img {
max-width: 100%;
height: auto;
}

View File

@ -1,295 +1,13 @@
// https://github.com/richleland/pygments-css/blob/master/zenburn.css
// https://github.com/mgyongyosi/OneDarkJekyll/blob/master/syntax-one-dark.css
// highly modified
/* stylelint-disable */
.highlight pre {
color: #fdce93;
color: $code-color;
background-color: $code-bg;
}
.highlight .hll {
background-color: #222;
}
.highlight .c {
color: #7f9f7f;
}
.highlight .err {
color: #e37170;
background-color: #3d3535;
}
.highlight .g {
color: #7f9f7f;
}
.highlight .k {
color: #f0dfaf;
}
.highlight .l {
color: #ccc;
}
.highlight .n {
color: #dcdccc;
}
.highlight .o {
color: #f0efd0;
}
.highlight .x {
color: #ccc;
}
.highlight .p {
color: #41706f;
}
.highlight .cm {
color: #7f9f7f;
}
.highlight .cp {
color: #7f9f7f;
}
.highlight .c1 {
color: #7f9f7f;
}
.highlight .cs {
color: #cd0000;
font-weight: bold;
}
.highlight .gd {
color: #cd0000;
}
.highlight .ge {
color: #ccc;
font-style: italic;
}
.highlight .gr {
color: red;
}
.highlight .gh {
color: #dcdccc;
font-weight: bold;
}
.highlight .gi {
color: #00cd00;
}
.highlight .go {
color: gray;
}
.highlight .gp {
color: #dcdccc;
font-weight: bold;
}
.highlight .gs {
color: #ccc;
font-weight: bold;
}
.highlight .gu {
color: purple;
font-weight: bold;
}
.highlight .gt {
color: #0040D0;
}
.highlight .kc {
color: #dca3a3;
}
.highlight .kd {
color: #ffff86;
}
.highlight .kn {
color: #dfaf8f;
font-weight: bold;
}
.highlight .kp {
color: #cdcf99;
}
.highlight .kr {
color: #cdcd00;
}
.highlight .kt {
color: #00cd00;
}
.highlight .ld {
color: #cc9393;
}
.highlight .m {
color: #8cd0d3;
}
.highlight .s {
color: #cc9393;
}
.highlight .na {
color: #9ac39f;
}
.highlight .nb {
color: #efef8f;
}
.highlight .nc {
color: #efef8f;
}
.highlight .no {
color: #ccc;
}
.highlight .nd {
color: #ccc;
}
.highlight .ni {
color: #c28182;
}
.highlight .ne {
color: #c3bf9f;
font-weight: bold;
}
.highlight .nf {
color: #efef8f;
}
.highlight .nl {
color: #ccc;
}
.highlight .nn {
color: #8fbede;
}
.highlight .nx {
color: #ccc;
}
.highlight .py {
color: #ccc;
}
.highlight .nt {
color: #9ac39f;
}
.highlight .nv {
color: #dcdccc;
}
.highlight .ow {
color: #f0efd0;
}
.highlight .w {
color: #ccc;
}
.highlight .mf {
color: #8cd0d3;
}
.highlight .mh {
color: #8cd0d3;
}
.highlight .mi {
color: #8cd0d3;
}
.highlight .mo {
color: #8cd0d3;
}
.highlight .sb {
color: #cc9393;
}
.highlight .sc {
color: #cc9393;
}
.highlight .sd {
color: #cc9393;
}
.highlight .s2 {
color: #cc9393;
}
.highlight .se {
color: #cc9393;
}
.highlight .sh {
color: #cc9393;
}
.highlight .si {
color: #cc9393;
}
.highlight .sx {
color: #cc9393;
}
.highlight .sr {
color: #cc9393;
}
.highlight .s1 {
color: #cc9393;
}
.highlight .ss {
color: #cc9393;
}
.highlight .bp {
color: #efef8f;
}
.highlight .vc {
color: #efef8f;
}
.highlight .vg {
color: #dcdccc;
}
.highlight .vi {
color: #ffffc7;
}
.highlight .il {
color: #8cd0d3;
}
.highlight .hll{background:#282c34}.highlight .c{color:darken($brand-main-blue-light, 15%);font-style:italic}.highlight .err{color:#960050;background-color:#1e0010}.highlight .k{color:$brand-main-violet;font-weight: bold}.highlight .l{color:#98c379}.highlight .n{color:$code-color}.highlight .o{color:$code-color}.highlight .p{color:$code-color}.highlight .cm{color:darken($brand-main-blue-light, 15%);font-style:italic}.highlight .cp{color:darken($brand-main-blue-light, 15%);font-style:italic}.highlight .c1{color:darken($brand-main-blue-light, 15%);font-style:italic}.highlight .cs{color:darken($brand-main-blue-light, 15%);font-style:italic}.highlight .ge{font-style:italic}.highlight .gs{font-weight:700}.highlight .kc{color:$brand-main-violet;font-weight: bold}.highlight .kd{color:$brand-main-violet;font-weight: bold}.highlight .kn{color:$brand-main-violet;font-weight: bold}.highlight .kp{color:$brand-main-violet;font-weight: bold}.highlight .kr{color:$brand-main-violet;font-weight: bold}.highlight .kt{color:$brand-main-violet;font-weight: bold}.highlight .ld{color:#98c379}.highlight .m{color:#d19a66}.highlight .s{color:#98c379}.highlight .na{color:#d19a66}.highlight .nb{color:#e5c07b}.highlight .nc{color:#e5c07b}.highlight .no{color:#e5c07b}.highlight .nd{color:#e5c07b}.highlight .ni{color:#e5c07b}.highlight .ne{color:#e5c07b}.highlight .nf{color:$code-color}.highlight .nl{color:#e5c07b}.highlight .nn{color:$code-color}.highlight .nx{color:$code-color}.highlight .py{color:#e5c07b}.highlight .nt{color:#e06c75}.highlight .nv{color:#e5c07b}.highlight .ow{font-weight:700}.highlight .w{color:#f8f8f2}.highlight .mf{color:#d19a66}.highlight .mh{color:#d19a66}.highlight .mi{color:#d19a66}.highlight .mo{color:#d19a66}.highlight .sb{color:#98c379}.highlight .sc{color:#98c379}.highlight .sd{color:#98c379}.highlight .s2{color:#98c379}.highlight .se{color:#98c379}.highlight .sh{color:#98c379}.highlight .si{color:#98c379}.highlight .sx{color:#98c379}.highlight .sr{color:#56b6c2}.highlight .s1{color:#98c379}.highlight .ss{color:#56b6c2}.highlight .bp{color:#e5c07b}.highlight .vc{color:#e5c07b}.highlight .vg{color:#e5c07b}.highlight .vi{color:#e06c75}.highlight .il{color:#d19a66}.highlight .gu{color:#75715e}.highlight .gd{color:#f92672}.highlight .gi{color:#a6e22e}
/* stylelint-enable */

View File

@ -7,27 +7,30 @@
li { padding-left: 0; }
&:before {
@extend .h1;
content: 'Table Of Contents';
@extend .h5;
content: 'Contents';
font-size: $font-size-lg;
display: block;
border-bottom: 1px solid $brand-main-blue-light;
padding-bottom: $spacer;
margin-bottom: ($spacer * 2);
text-align: center;
margin-top: 0;
}
li,
ol { margin: 0; }
ol,
ul { margin: 0; }
li {
display: block;
}
> li {
// custom numbers
&:before {
content: counters(item, '.') ' ';
content: counters(item, '.') '. ';
counter-increment: item;
margin-right: $spacer;
color: $brand-main-gray;
margin-right: $spacer / 4;
color: $brand-main-gray-light;
width: 1rem;
display: inline-block;
}
}
}
@ -35,7 +38,8 @@
// output by Kramdown
/* stylelint-disable selector-no-id */
#markdown-toc {
#markdown-toc,
.section-nav {
@extend .toc;
}

View File

@ -60,7 +60,7 @@ $line-height: 1.5 !default;
$headings-font-family: inherit !default;
$headings-font-weight: $font-weight-light !default;
$headings-line-height: 1.3 !default;
$headings-line-height: 1.2 !default;
$headings-color: $brand-main-blue-light !default;
@ -113,15 +113,15 @@ $gutter-space: ($spacer * 2) !default;
//
// Code
//
$code-color: $text-color !default;
$code-bg: $gray-dark !default;
$code-color: $brand-main-gray-light !default;
$code-bg: darken($gray-dark, 5%) !default;
$kbd-color: $code-color !default;
$kbd-bg: $code-bg !default;
$pre-bg: $code-bg !default;
$pre-color: $code-color !default;
$pre-scrollable-max-height: 340px !default;
$pre-scrollable-max-height: 28rem !default;
//

View File

@ -51,18 +51,12 @@ drivers:
# ----------------------------
docs:
title: "Documentation"
description: "Dive into our documentation with tutorials, examples, terminology, references and more."
button: "See All Documentation"
title: "Guides & Documentation "
description: "Dive into our documentation with guides, examples, terminology, references and more."
button_documentation: "See All Documentation"
button_guides: "See All Guides"
categories:
- title: "Tutorials"
items:
- title: "Set Up & Run a Dev/Test Node"
link: "https://docs.bigchaindb.com/projects/server/en/latest/dev-and-test/setup-run-node.html"
- title: "Production Deployment Template"
link: "https://docs.bigchaindb.com/projects/server/en/latest/production-deployment-template/index.html"
- title: "Code Examples"
items:
- title: "Basic Usage Examples"

View File

@ -6,8 +6,8 @@ main:
url: "/features/"
- title: Use Cases
url: "/usecases/"
- title: Enterprise
url: "/enterprise/"
- title: Guides
url: "/guides/"
- title: Docs
url: https://docs.bigchaindb.com/
@ -18,6 +18,10 @@ secondary:
url: "/about/"
- title: Blog
url: https://blog.bigchaindb.com
- title: Enterprise
url: "/enterprise/"
- title: Whitepaper
url: "/whitepaper/"
- title: Contact
url: "/contact/"

19
_src/_guides/_setup.md Normal file
View File

@ -0,0 +1,19 @@
# Setup
Start by installing the official [BigchainDB JavaScript driver](https://github.com/bigchaindb/js-bigchaindb-driver):
```bash
npm i bigchaindb-driver
```
Then, include that as a module and connect to any BigchainDB node. You can create your own `app_id` and `app_key` on [BigchainDB Testnet](https://testnet.bigchaindb.com).
```js
const BigchainDB = require('bigchaindb-driver')
const API_PATH = 'https://test.bigchaindb.com/api/v1/'
const conn = new BigchainDB.Connection(API_PATH, {
app_id: 'Get one from testnet.bigchaindb.com',
app_key: 'Get one from testnet.bigchaindb.com'
})
```

View File

@ -0,0 +1,245 @@
---
layout: guide
title: "Tutorial: How to create a pull request with different conditions for reviews"
tagline: Learn how to use crypto-conditions for pull requests in GitHub using signatures for reviews, assignments and merges.
header: header-crypto.jpg
order: 4
learn: >
- How to use cryptoconditions in BigchainDB
---
Hi there! Welcome to our next tutorial about crypto-conditions. For this tutorial, we assume that you are familiar with the BigchainDB primitives (assets, inputs, outputs, transactions etc.). If you are not, familiarize yourself with the [Key concepts of BigchainDB](../key-concepts-of-bigchaindb/). We also assume that you have completed our [first tutorial](../tutorial-car-telemetry-app/) and have a basic understanding of [crypto-conditions.](https://the-ipdb-transaction-spec.readthedocs.io/en/latest/transaction-components/conditions.html)
# About GitHub issues and pull requests
The interaction among developers on Github is a prime example of collaboration, where multiple parties usually need to coordinate, align and approve different suggestions. This makes it a useful example for the potential usage of a BigchainDB feature: crypto-conditions. Crypto-conditions are a tool that allows to design complex signature schemes, where multiple parties need to sign to approve, respectively trigger and event.
Today, GitHub gives you the possibility of signing your commits before publishing that. Leveraging that, you could use crypto-conditions to create different conditions that need to be fulfilled before merging a pull request (PR).
For the sake of the tutorial, think of the following setting: let's imagine you belong to a very cool startup called "SmartAntsLabs" based in Berlin. The start-up works with open-source projects. Now you have discovered a bug and you want to report it. You create an issue on Github and you accept a PR to solve the issue. You expect the developer team to make a contribution to this PR. At least one of them should create a commit in the PR. Once that happens and the PR is ready, someone needs to assign it to the QA team. In the QA team let's imagine there is needed 3 total votes. Then once that happens it could be send it to the production where just 1 signature out of 3 people who belong to this team is needed to merge the pull request.
{% include_relative _setup.md %}
# Create threshold-sha-256 condition
So, first things first. Initially, you need to represent the Github issue as an asset in BigchainDB. But it will have special conditions, as in the output you should indicate that just one signature (one private key) is needed in order to send the Pull request associated with it to the QA team. So imagine there are 3 developers in your SmartAntsLabs startup.
```js
//Users will be needed to create the cryptoconditions
const dev1 = new BigchainDB.Ed25519Keypair()
const dev2 = new BigchainDB.Ed25519Keypair()
const dev3 = new BigchainDB.Ed25519Keypair()
// The creator of the issue
const creator = new BigchainDB.Ed25519Keypair()
// at the output of the transaction to-be-spent
// Set threshold 1, so just one signature is needed to create the PR and send it to the QA team.
const threshold = 1
const condition1 = BigchainDB.Transaction.makeEd25519Condition(dev1.publicKey, false)
const condition2 = BigchainDB.Transaction.makeEd25519Condition(dev2.publicKey, false)
const condition3 = BigchainDB.Transaction.makeEd25519Condition(dev3.publicKey, false)
const thresholdCondition = BigchainDB.Transaction.makeThresholdCondition(threshold, [condition1, condition2, condition3])
```
Each condition is of type Ed25519, and combining together you can create the so called Threshold Condition. Set parameter `threshold` to 1, as it will just need 1 of the developers, no matters who of them, to sign later the transaction.
# Fulfill inputs in different ways
Now with the `thresholdCondition` you can generate an output in the same way you used to do it, calling the `makeOutput` method of the Js driver
```js
let output = BigchainDB.Transaction.makeOutput(thresholdCondition);
// Set public keys, as the makeThresholdCondition does not that
output.public_keys = [dev1.publicKey, dev2.publicKey, dev3.publicKey];
// Create the transaction
let makeTransaction = BigchainDB.Transaction.makeCreateTransaction({
issue: '#16',
datetime: new Date().toString()
},
// Metadata contains information about the transaction itself
// (can be `null` if not needed)
{
state: 'Issue created.'
},
// Output
[output],
// Issuers
creator.publicKey
)
// Sign the transaction with private key of the creator
const txSigned = BigchainDB.Transaction.signTransaction(makeTransaction, creator.privateKey)
// Send the transaction to BigchainDB
conn.postTransaction(txSigned)
.then(() => conn.pollStatusAndFetchTransaction(txSigned.id))
.then(res => {
document.body.innerHTML +='<h3>Transaction created</h3>';
document.body.innerHTML +=txSigned.id
})
```
Apart from make the output with the correspond function, you need to provide the public keys of the users who will have the ownership of that output. Then you just create the transaction with the output that you have created, and the signature of the creator of the pull request.
In this way you are transferring the ownership of the issue to the developers. They will have now the chance to work with this object in BigchainDB, and just with one signatures of them will be enough to transfer this object in BigchainDB again.
So let's imagine that a developer of SmartAntsLabs has fixed the issue in a new pull request that he has created. He provides his private key in order to make a transfer transaction in BighchainDB and give the ownership of it to the QA person. She will be the only one who can review it, give an okey and moving forward with the PR.
```js
function createPR() {
// Transfer the asset to the QA team
const QAperson = new BigchainDB.Ed25519Keypair()
let createTranfer = BigchainDB.Transaction.makeTransferTransaction(
txSigned,
{
state: "Pull request created"
}, [BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction.makeEd25519Condition(receiver.publicKey))],
0
)
// at the input of the spending transaction
// Create and sign fulfillments to fulfill the cryptoconditions. Just one signature is enough, then one private keys is needed.
let fulfillment1 = BigchainDB.Transaction.makeEd25519Condition(dev2.publicKey, false)
//Sign the fulfillment with the created transfer
fulfillment1.sign(
new Buffer(BigchainDB.Transaction.serializeTransactionIntoCanonicalString(createTranfer)),
new Buffer(base58.decode(dev2.privateKey))
)
const threshold = 1
// 1 out of 3 need to sign the fulfillment. Still condition1 and condition3 are needed as the "circuit definition" is needed.
// See https://github.com/bigchaindb/cryptoconditions/issues/94
let fulfillment = BigchainDB.Transaction.makeThresholdCondition(threshold, [fulfillment1, condition1, condition3], false)
const fulfillmentUri = fulfillment.serializeUri()
// Finally set the fulfillment for the input. That is to sign the transaction
createTranfer.inputs[0].fulfillment = fulfillmentUri
// Post the transaction to BigchainDB
conn.postTransaction(createTranfer)
.then(() => conn.pollStatusAndFetchTransaction(createTranfer.id))
.then(res => {
document.body.innerHTML +='<h3>Transaction created</h3>';
document.body.innerHTML +=createTranfer.id
})
}
```
Now the ball is in the QA person. She reviews the impact in the UI of the software, do some tests and she is ready to approve the changes. Once that happens the PR will be send to the production team. They are going to make sure while testing in the test network that the changes made work seamless and are ready for a production environment.
In the production team of SmartAntsLabs there are 4 people but with different experience as there is one intern and recently one person has joined the super SmartAntsLabs startup. So with his review the PR will not be approved as there should be someone with more experience who also review the the PR. In order to create this scenario, the intern will have 1 vote as well as an early employee and the two other two seniors production women will have 2 votes each one.
```js
//Production team
const intern = new BigchainDB.Ed25519Keypair()
const earlyEmployee = new BigchainDB.Ed25519Keypair()
const senior1 = new BigchainDB.Ed25519Keypair()
const senior2 = new BigchainDB.Ed25519Keypair()
// At the output of the transaction to-be-spent
// Create subcondition where early employee and intern have to approve. Is a 2 out of 2
const thresholdSubconditions = 2
const subCondition1 = BigchainDB.Transaction.makeEd25519Condition(intern.publicKey, false)
const subCondition2 = BigchainDB.Transaction.makeEd25519Condition(earlyEmployee.publicKey, false)
const condition3 = BigchainDB.Transaction.makeThresholdCondition(thresholdSubconditions, [subCondition1, subCondition2], false)
// Then create the other scenarios. All together is a 1 out of 3, as just one scenario is needed
const thresholdProduction = 1
const condition1 = BigchainDB.Transaction.makeEd25519Condition(senior1.publicKey, false)
const condition2 = BigchainDB.Transaction.makeEd25519Condition(senior2.publicKey, false)
//Threshold of the whole scenarios
const thresholdCondition = BigchainDB.Transaction.makeThresholdCondition(thresholdProduction, [condition1, condition2, condition3])
let output = BigchainDB.Transaction.makeOutput(thresholdCondition);
// Set public keys, as the makeThresholdCondition does not that. All of the public keys involved in any subcondition are needed
output.public_keys = [senior1.publicKey, senior2.publicKey, inter.publicKey, earlyEmployee.publicKey];
// Create the transfer transaction
let createTranfer = BigchainDB.Transaction.makeTransferTransaction(
txSigned,
{
state: "Send to production"
},
[output],
0
)
// Sign the transaction with private key of the qa person
const transferToProduction = BigchainDB.Transaction.signTransaction(createTranfer, QAperson.privateKey)
// Send the transaction to BigchainDB
conn.postTransaction(transferToProduction)
.then(() => conn.pollStatusAndFetchTransaction(transferToProduction.id))
.then(res => {
document.body.innerHTML ='<h3>Transfer transaction created</h3>';
document.body.innerHTML +=transferToProduction.id
})
```
Generally there is a threshold condition 1 out of 3 possible scenarios:
1. Senior 1 approves
2. Senior 2 approves
3. Intern and early employee approve
So just with the occurrence of one, the next transfer transaction can be done. For that first you create a subcondition which is that both the intern and the early employee has to sign to fulfill this subcondition. That is represented as `condition3` in the code, then with the other conditions of the senior members you can create the threshold condition. Finally the QA person signs the transaction and send it to BigchainDB.
Is the turn of the production team. The intern starts to look at the issue, try to run it but the senior is on the same task and harnessing her experience she finish the review before and approve the PR and merge it to the master branch.
```js
// Public key that private key is very difficult to generate
const burnPublicKey = 'burnburnburnburnburnburnburnburnburnburnburn'
// Create the transfer transaction
let transferApprove = BigchainDB.Transaction.makeTransferTransaction(
transferToProduction,
{
state: "Approved. Merged"
},
[[BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction.makeEd25519Condition(burnPublicKey.publicKey))]],
0
)
let fulfillmentSenior = BigchainDB.Transaction.makeEd25519Condition(senior1.publicKey, false)
// The only one that need to sign is the senior1
fulfillment1.sign(
new Buffer(BigchainDB.Transaction.serializeTransactionIntoCanonicalString(transferApprove)),
new Buffer(base58.decode(senior1.privateKey))
);
// Still condition1 and condition3 are needed as the "circuit definition" is needed.
let fulfillment = BigchainDB.Transaction.makeThresholdCondition(threshold, [fulfillmentSenior, condition2, condition3],false)
//Sign the transaction
const fulfillmentUri = fulfillment.serializeUri()
transferApprove.inputs[0].fulfillment = fulfillmentUri
conn.postTransaction(transferApprove)
.then(() => conn.pollStatusAndFetchTransaction(transferApprove.id))
.then(res => {
document.body.innerHTML ='<h3>Transfer transaction created</h3>';
document.body.innerHTML +=transferApprove.id
})
```
The public key `burnPublicKey` is such that is very unlikely and almost impossible to generate a private key that match with this public key, so none will be able to use fulfill the condition for this output for making an input of a transaction with it. Just a senior person is needed, so as long as there is a fulfillment signed with a private key from a senior, the transaction can be done.
That's it! Now you know, how cryptoconditions in BigchainDB can be used to create a pull request with different conditions and roles in order to merge it.

BIN
_src/_guides/diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

BIN
_src/_guides/diagram@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 KiB

BIN
_src/_guides/header-art.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
_src/_guides/header-car.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -0,0 +1,85 @@
---
layout: guide
title: Key concepts of BigchainDB
tagline: "Get familiar with our transaction model (Assets, Inputs, Outputs, and Transactions)"
order: 1
learn: >
- How BigchainDB's transaction model works
- What each component in a transaction represents
- What a `CREATE` transaction is
- What a `TRANSFER` transaction is
---
# About our transaction model
The first thing to understand about BigchainDB is how we structure our data. Traditional SQL databases structure data in tables. NoSQL databases use other formats to structure data such as JSON and key-values, as well as tables. At BigchainDB, we structure data as assets. We believe anything can be represented as an asset. An asset can characterize any physical or digital object that you can think of like a car, a data set or an intellectual property right.
These assets can be registered on BigchainDB in two ways. (1) By users in `CREATE` transactions. (2) Transferred (or updated) to other users in `TRANSFER` transactions.
Traditionally, people design applications focusing on business processes (e.g. apps for booking & processing client orders, apps for tracking delivery of products etc). At BigchainDB, we dont focus on processes rather on assets (e.g. a client order can be an asset that is then tracked across its entire lifecycle). This switch in perspective from a process-centric towards an asset-centric view influences much of how we build applications.
# Visualization of our transaction model
This infographic will help you understanding what `CREATE` and `TRANSFER` transactions are and what the individual components of a transaction represent (inputs, outputs, assets, metadata etc.). Let's use a simple real-life example: Martina digitally registers her bicycle on BigchainDB in a `CREATE` transaction. After some time, she transfers this bicycle to Stefan in a `TRANSFER` transaction.
Every concept that we describe (e.g. inputs, outputs etc.) is discussed in further detail below.
<img class="image--create-transfer" src="../diagram.png" srcset="../diagram@2x.png 2x, ../diagram.png 1x" alt="BigchainDB CREATE and TRANSFER transactions" />
The data model of transactions is explained in our [transaction model](https://docs.bigchaindb.com/projects/server/en/latest/data-models/transaction-model.html).
# Asset
An asset can represent any physical or digital object. It can be a physical object like a car or a house. Or it can be a digital object like a customer order or an air mile. An asset can have one or multiple owners, but it can also be its own owner. Think of an autonomous car or an IoT sensor that does transactions automatically. More information about the asset data model can be found in our [asset model](https://docs.bigchaindb.com/projects/server/en/latest/data-models/asset-model.html). An asset always contains data that is immutable. In our example, the color and the registration number of a bicycle is immutable data.
Depending on the context, an asset can represent many different things.
### An asset as a claim
An asset can represent an ownership claim for a particular object, e.g. it represents a claim that User ABC owns the bicycle with the number XYZ. This can be valid for any type of ownership.
### An asset as a token
An asset can also represent a token. BigchainDB supports divisible assets. This means, multiple assets can be issued and attributed to one overarching asset. This can for instance be interesting for token launches.
### An asset as a versioned document
An asset can also be a versioned document with the version stated in the metadata field. The version of this document can be updated on a continuous basis. Every time there is a new version of the document, it could be reflected in the metadata. For further information refer to our [blog](https://blog.bigchaindb.com/crab-create-retrieve-append-burn-b9f6d111f460).
### An asset as a time series
An asset can also represent a time series of data. For instance, an IoT sensor records its own data. The IoT sensor is the asset and every submission of its data (e.g. temperature) is represented as an update in the metadata with the latest temperature that the IoT sensor measured.
### An asset as a state machine
An asset can also be a state machine where the state transition is represented in the metadata. Each time the machine changes its state, a transaction is triggered to update the metadata to the new state (possibility to listen to it with the WebSocket).
### An asset as a permission (RBAC)
Assets could also be: roles, users, messages, (and anything which can have multiple instances in a scenariovehicles, reports, and so on). Find more information on our [blog](https://blog.bigchaindb.com/role-based-access-control-for-bigchaindb-assets-b7cada491997).
As you can see, there are almost no limits with respect to what an asset can represent.
# Input
Conceptually, an input is a pointer to an output of a previous transaction. It specifies to whom an asset belonged before and it provides a proof that the conditions required to transfer the ownership of that asset (e.g. a person needs to sign) are fulfilled. In a CREATE transaction, there is no previous owner, so an input in a CREATE transaction simply specifies who the person is that is registering the object (this is usually the same as the initial owner of the asset). In a TRANSFER transaction, an input contains a proof that the user is authorized to "spend" (transfer or update) this particular output. In practical terms, this means that with the input, a user is stating which asset (e.g. the bike) should be transferred. He also demonstrates that he or she is authorized to do the transfer of that asset. Learn more about the structure of inputs in our [input model](https://docs.bigchaindb.com/projects/server/en/latest/data-models/inputs-outputs.html#inputs).
# Output
A transaction output specifies the conditions that need to be fulfilled to change the ownership of a specific asset. For instance: to transfer a bicycle, a person needs to sign the transaction with his or her private key. This also implicitly contains the information that the public key associated with that private key is the current owner of the asset. Learn more about the data model of outputs in our [output model](https://docs.bigchaindb.com/projects/server/en/latest/data-models/inputs-outputs.html#outputs).
Note that a transaction can also have multiple outputs. These are called divisible assets. To learn more about divisible assets, complete our [tutorial.](../tutorial-token-launch/) The output can also contain complex conditions (e.g. multiple signatures of multiple people) to acquire ownership. Learn more about that in the data model for [crypto-conditions](https://docs.bigchaindb.com/projects/server/en/latest/data-models/conditions.html).
# Metadata
The metadata field allows users to add additional data to a transaction. This can be any type of data, like the age of a bicycle or the kilometers driven. The good thing about the metadata is that it can be updated with every transaction. In contrast to the data in the asset field, the metadata field allows to add new information to every transaction. Additionally, with the release of BigchainDB V1.3, we introduced the ability to query for metadata. Read more about that on our [blog.](https://blog.bigchaindb.com/bigchaindb-version-1-3-7940cc60c767)
# Transaction ID
The ID of a transaction is a unique hash that identifies a transaction. It contains all the information about the transaction in a hashed way. Find out more about the cryptography BigchainDB uses [here.](https://docs.bigchaindb.com/projects/server/en/latest/appendices/cryptography.html)
That's it! Now you're familiar with our transaction model and ready to complete our first [tutorial](../tutorial-piece-of-art/) and get started on BigchainDB!

View File

@ -0,0 +1,186 @@
---
layout: guide
title: "Tutorial: How to create a digital twin of your car"
tagline: Build a telemetry app to digitally track the mileage of a car
header: header-car.jpg
order: 3
learn: >
- How BigchainDB can be used to record dynamic parameters of an asset
- How decentralized identifiers can represent objects in BigchainDB
- How asset metadata is updated by using `TRANSFER` transactions to change the state of an asset (the mileage of a car in our example)
---
Hi there! Welcome to our next tutorial! For this tutorial, we assume that you are familiar with the BigchainDB primitives (assets, inputs, outputs, transactions etc.). If you are not, familiarize yourself with [Key concepts of BigchainDB](../key-concepts-of-bigchaindb/).
# About digital twins
We are moving towards an era where the Internet of Things is becoming real. Cars become more connected, devices equipped with sensors can communicate their data, and objects become smarter and smarter. This triggers the need for a digital representation of these devices to store their data in a safe location and to have a complete audit trail of their activity. This is the core idea of the digital twin of an object.
BigchainDB is an ideal solution to create digital twins of smart devices. In this tutorial, you will learn how to build a simple and basic version of a digital twin of your car, which allows its owner to store and update the mileage of the car. The car contains a GPS tracker to submit the mileage and the car, as well as the GPS sensor will have their own identity.
Let's get started!
{% include_relative _setup.md %}
# Creation of a key pair
In BigchainDB, users are represented as a private and public key pair. In our case, a key pair for Alice will be created.
For Alice, you can generate a key pair from a seed phrase using the BIP39 library, so you will just need to remember this particular seed phrase. The code below illustrates that.
```js
const alice = new BigchainDB.Ed25519Keypair(bip39.mnemonicToSeed('seedPhrase').slice(0,32))
```
# Decentralized Identifier Class
In telemetry applications, certain objects like in our case e.g. the car, need to have an identity to conduct actions in the system. Ideally, this identity is not controlled by anyone, such that the device can truly act autonomously. For these use cases, in BigchainDB we will use decentralized identifiers (DID) which are identifiers intended for verifiable digital identity that is "self-sovereign". They do not dependent on a centralized registry, identity provider, or certificate authority. You can learn more about it in our [DID specification](https://w3c-ccg.github.io/did-spec/).
So in our app, each object in the real world as the car, the telemetry box in the car, the GPS device, etc. will be represented by a DID. Each object will have a tag or cryptochip containing a securely hidden private key that serves as unique identity.
You will create a DID class that inherits from Orm BigchainDB driver, so DID objects will have all of the methods available in Orm. The `entity` represents the public key of the object itself.
```js
class DID extends Orm {
constructor(entity) {
super(
API_PATH, {
app_id: 'Get one from testnet.bigchaindb.com',
app_key: 'Get one from testnet.bigchaindb.com'
}
)
this.entity = entity
}
}
```
So as now each object has its own keypair, it is possible to create a DID from each object. The objects are thus "self-sovereign", there is not a central authority that controls them. They will just have a user or another object that will have the ownership over them. Because in our Orm driver, a model is needed, the default one can be used for this tutorial.
```js
const car = new driver.Ed25519Keypair()
const sensorGPS = new driver.Ed25519Keypair()
const userDID = new DID(alice.publicKey)
const carDID = new DID(car.publicKey)
const gpsDID = new DID(sensorGPS.publicKey)
userDID.define("myModel", "https://schema.org/v1/myModel")
carDID.define("myModel", "https://schema.org/v1/myModel")
gpsDID.define("myModel", "https://schema.org/v1/myModel")
```
As you can see, every object or actor (alice, car, GPS sensor) has now it's own key pair and identity in our system.
# Digital registration of assets on BigchainDB
After having generated key pairs (and identities), you can now create the actual assets in BigchainDB. There will be three assets in our system: the car, the user and the GPS sensor. Therefore, as a first step you will create an asset representing each object. As decentralized identifiers are used, you can easily call the `create` method that each of them have and an asset will be created.
These assets will now live in BigchainDB forever and there is no possibility to delete them. This is the immutability property of blockchain technology.
For creating the first asset you can generate a `CREATE` transaction that represents the user DID in BigchainDB as an asset. The user is a self-owned identity, so you will use Alice's keypair to create the `userDID`.
```js
userDID.myModel.create({
keypair: alice,
data: {
name: 'Alice',
bithday: '03/08/1910'
}
}).then(asset => {
userDID.id = 'did:' + asset.id
document.body.innerHTML +='<h3>Transaction created</h3>'
document.body.innerHTML +=asset.id
})
```
As you can see, by inheriting the Orm class it is very easy to create an asset in BigchainDB. The only thing needed is the keypair and the asset.
The id property is set in the DID object. This is the unique identifier of this asset.
In order to create the asset of the car you first need to define the asset field that represents the car. It has a JSON format:
```js
const vehicle = {
value: '6sd8f68sd67',
power: {
engine: '2.5',
hp: '220 hp',
}
consumption: '10.8 l',
}
```
Now you can create the DID for the car. The owner of the car is Alice, and she is the one who can transfer this asset in the future, so the Alice keypair is needed to create this asset
```js
carDID.myModel.create({
keypair: alice,
data: {
vehicle
}
}).then(asset => {
carDID.id = 'did:' + asset.id
document.body.innerHTML +='<h3>Transaction created</h3>'
document.body.innerHTML +=txTelemetrySigned.id
})
```
For the GPS and any other piece of the car, the car is the owner of those assets, so you will need the car keypair to create these assets
```js
gpsDID.myModel.create({
keypair: car,
data: {
gps_identifier: 'a32bc2440da012'
}
}).then(asset => {
gpsDID.id = 'did:' + asset.id
document.body.innerHTML +='<h3>Transaction created</h3>'
document.body.innerHTML +=txTelemetrySigned.id
})
```
Now you have digitally registered the parts of the car on BigchainDB, respectively in our case on the BigchainDB test network.
Once a transaction ends up in a decided-valid block, it's "etched into stone". There's no changing it, no deleting it. The asset is registered now and cannot be deleted. However, the usage of the metadata field allows you to append new information in the future.
# Update of an asset on BigchainDB
In the Orm driver a so called "Update" in a normal Database, is called "Append" in blockchain, as no data can be really deleted or updated. So in order to track the mileage of the car, the GPS piece will append a new transaction containing the new updated mileage in the metadata.
Since an update of the mileage of a car does not imply any change in the ownership, your transfer transaction will simply be a transfer transaction with the previous owner (car) as beneficiary, but with new metadata in the transaction. So, technically, the car is transferring the GPS to itself and just adding additional, new information to that transaction.
```js
function updateMileage(did, newMileage){
did.myModel
.retrieve(did.id)
.then(assets => {
// assets is an array of myModel
// the retrieve asset contains the last (unspent) state
// of the asset
return assets[0].append({
toPublicKey: car.publicKey,
keypair: car,
data: { newMileage }
})
})
.then(updatedAsset => {
did.mileage = updatedAsset.data.newMileage
document.body.innerHTML +='<h3>Append transaction created</h3>'
document.body.innerHTML +=txTelemetrySigned.id
return updatedAsset
})
}
```
So, finally you have now updated your asset and it is now recorded that your car has driven a distance of `newMileage`.
That's it, we have created a car asset, and every time the car travels new kilometers the `updateMileage` will be called with the new value of it, which leads to a continuous update in the car mileage.
Congratulations! You have successfully finished your first BigchainDB tutorial.

View File

@ -0,0 +1,154 @@
---
layout: guide
title: "Tutorial: How to create a digital record of a piece of art"
tagline: Build a digital certificate of a famous painting that you own
header: header-art.jpg
order: 2
learn: >
- How assets can be used on BigchainDB to represent real objects
- How to make a `CREATE` transaction to digitally register an asset on BigchainDB
- How to create `TRANSFER` transactions to change the ownership of an asset in BigchainDB
- How BigchainDB can be used to record dynamic parameters of an asset
---
Hi there! Welcome to our first tutorial! For this tutorial, we assume that you are familiar with the BigchainDB primitives (assets, inputs, outputs, transactions etc.). If you are not, familiarize yourself with [Key concepts of BigchainDB](../key-concepts-of-bigchaindb/).
# About digital representations of assets
We are moving towards an era where every physical object has a digital representation in a database. This can be in the form of a certificate, a simple entry in a database or another form of digital footprint. In the past, this used to be the paper trail associated with the purchase of a car, a painting or any other type of asset. Today, digital is slowly replacing analog in most aspects of our life. Thanks to advances in cryptography, we are reaching a point where even ownership claims of a specific object don't need to be a signed paper certificate anymore. This allows digitization to move to a new level. BigchainDB as a solution is suited perfectly to act as a digital asset registration and tracking tool.
Using the example of the digital registration of a famous painting you own, in this tutorial you will learn how to register an asset on BigchainDB and how to digitally transfer the ownership of this asset to someone else. The example is for illustrative purposes. For a real life application, there would be additional components that would need to be included.
Let's get started!
{% include_relative _setup.md %}
# Creation of a key pair
Before starting, you need to create a user in BigchainDB. In BigchainDB, users are represented as a private and public key pair. In our case, a key pair for Alice will be created. Alice will be the owner of the painting, and she will be the only one able to make changes to the digital representation of the painting. Using her public key, anyone can also verify that Alice is the owner of the painting.
You can generate a key pair from a seed phrase using the BIP39 library, so you will just need to remember this particular seed phrase. The code below illustrates that.
```js
const alice = new BigchainDB.Ed25519Keypair(bip39.mnemonicToSeed('seedPhrase').slice(0,32))
```
# Digital registration of an asset on BigchainDB
Now, let's assume that Alice is extremely lucky and gets to acquire the famous painting "Las Meninas" by the Spanish painter Diego Velázquez at a fantastic price during an auction held by the Spanish museum "museo nacional del prado". Now, she wants to ensure that she can digitally certify that she is the owner of this painting. For this reason, she wants to register the painting as an asset on BigchainDB to have an immutable claim. This corresponds to a CREATE transaction in BigchainDB. Using her key pair, Alice can create an asset on BigchainDB. In your case, the asset will represent an object in real life, namely the painting "Las Meninas". This asset will live in BigchainDB forever and there is no possibility to delete it.
The first step required is the definition of the asset field that represents the painting. This field contains the data about the asset that is immutable. It has a JSON format:
```js
const painting = {
name: 'Meninas',
author: 'Diego Rodríguez de Silva y Velázquez'
place: 'Madrid',
year: '1656'
}
```
As a next step, you need to generate a `CREATE` transaction to link the defined asset to the user Alice. There are three steps to post this transaction in BigchainDB. First you create it, then sign it and then send it. There are different methods for each step. Here, we are illustrating one of them:
```js
function createPaint() {
// Construct a transaction payload
const txCreatePaint = BigchainDB.Transaction.makeCreateTransaction(
// Asset field
{
painting,
},
// Metadata field, contains information about the transaction itself
// (can be `null` if not needed)
{
datetime: new Date().toString(),
location: 'Madrid',
value: {
value_eur: '25000000€',
value_btc: '2200',
}
},
// Output. For this case we create a simple Ed25519 condition
[BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction.makeEd25519Condition(alice.publicKey))],
// Issuers
alice.publicKey
)
// The owner of the painting signs the transaction
const txSigned = BigchainDB.Transaction.signTransaction(txCreatePaint,
alice.privateKey)
// Send the transaction off to BigchainDB
conn.postTransaction(txSigned)
// Check the status of the transaction
.then(() => conn.pollStatusAndFetchTransaction(txSigned.id))
.then(res => {
document.body.innerHTML += '<h3>Transaction created</h3>';
document.body.innerHTML += txSigned.id
// txSigned.id corresponds to the asset id of the painting
})
}
```
Now Alice has digitally registered her painting on BigchainDB. Alice's public key appears in the output, specifying that she is the owner of the painting. `txSigned.id` is an id that uniquely identifies your asset (your asset id). Note that the metadata field is used to record values along with the transaction (e.g. the price of the painting). This is a field that can be different in every transaction (as every transaction can have different metadata, because e.g. the price of the painting changes).
Once a transaction ends up in a decided-valid block, it's "etched into stone". There's no changing it, no deleting it. The asset is registered now and cannot be deleted. However, the usage of the metadata field allows you to do updates in the asset. For this, you can use `TRANSFER` transactions (with their arbitrary metadata) to store any type of information, including information that could be interpreted as changing an asset (if that's how you want it to be interpreted).
# Transfer of an asset on BigchainDB
Now, let's assume Alice has sold her painting in a good deal to someone else and she wants to digitally reflect that transfer. In BigchainDB, this would correspond to a TRANSFER transaction. For this, you first need to create a new key pair for a new owner (newOwner). For simplicity, this step is left out in the code below.
The `getTransaction` method allows us to search for a transaction having its id, as we need the complete transaction to make transfer transaction.
Based on that, we can now create the transfer transaction:
```js
function transferOwnership(txCreatedID, newOwner) {
const newUser = new BigchainDB.Ed25519Keypair()
// Get transaction payload by ID
conn.getTransaction(txCreatedID)
.then((txCreated) => {
const createTranfer = BigchainDB.Transaction.
makeTransferTransaction(
// The output index 0 is the one that is being spent
[{
tx: txCreated,
output_index: 0
}],
[BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction.makeEd25519Condition(
newOwner.publicKey))],
{
datetime: new Date().toString(),
value: {
value_eur: '30000000€',
value_btc: '2100',
}
}
)
// Sign with the key of the owner of the painting (Alice)
const signedTransfer = BigchainDB.Transaction
.signTransaction(createTranfer, alice.privateKey)
return conn.postTransaction(signedTransfer)
})
.then((signedTransfer) => conn
.pollStatusAndFetchTransaction(signedTransfer.id))
.then(res => {
document.body.innerHTML += '<h3>Transfer Transaction created</h3>'
document.body.innerHTML += res.id
})
}
```
Note again that in the output of this transfer transaction we have `newOwner.publicKey`. This shows that Alice has transferred the ownership of the Meninas to anybody else (newOwner). Furthermore, the input being spent is 0, as there is just one input. Additionally, note that the metadata field was used to update information about the painting (the price of the transaction, which increased to 30 mn. EUR etc.).
You have now updated your asset and it is now not anymore Alice who will be able to transfer the painting, because someone else is now the owner.
That's it, we have created a digital representation of a painting and transferred the ownership to another user.
Congratulations! You have successfully finished your first BigchainDB tutorial.

View File

@ -0,0 +1,231 @@
---
layout: guide
title: "Tutorial: Role-based access control in BigchainDB"
tagline: Learn how to assign different roles and permissions to different user types in BigchainDB
header: header-rbac.jpg
order: 4
learn: >
- How Role-based access control works in BigchainDB
---
Hi there! Welcome to our next tutorial about Role-based access controls (RBAC) in BigchainDB. For this tutorial, we assume that you are familiar with the BigchainDB primitives (assets, inputs, outputs, transactions etc.). If you are not, familiarize yourself with the [Key concepts of BigchainDB](../key-concepts-of-bigchaindb/). We also assume that you have completed our [first tutorial](../tutorial-car-telemetry-app/).
# About RBAC
Role based access control is a way to restrict the system access to certain users. In BigchainDB this function enables the creation of hierarchies of role and permissions as assets. Furthermore, users can be assigned roles to “act on behalf of” or “represent” other users or groups.
In our example use-case scenario for this guide, we have different tribes or groups of users where they have different roles, users belonging to one tribe can create proposal assets and others can create vote assets on the BigchainDB blockchain.
{% include_relative _setup.md %}
**Important note:** The BigchainDB RBAC module does not work out of the box in BigchainDB and a plugin [smart-assets](https://github.com/bigchaindb/bigchaindb-smart-assets) needs to be loaded with a specific [BigchainDB branch (kyber-master)](https://github.com/bigchaindb/bigchaindb/tree/kyber-master). The setup instructions are available in the [README.md](https://github.com/bigchaindb/bigchaindb-smart-assets/blob/master/README.md) of the smart-assets repository.
Let's create the app. You will create an asset for Admin type which will act as the admin group for the app. Async/await functions will be used in this tutorial
```js
const nameSpace = 'rbac-bdb-tutorial'
async function createApp(){
// Generate keypair for admin instance
const admin1 = new driver.Ed25519Keypair()
// Create admin user type. This is the asset representing the group of
// admins
const adminGroupAsset = {
ns: `${nameSpace}.admin`,
name: 'admin'
}
const adminGroupMetadata = {
canLink: [admin1.publicKey]
}
const adminGroupId = (await createNewAsset(admin1, adminGroupAsset,
adminGroupMetadata)).id
document.body.innerHTML ='<h3>Admin Group asset created</h3>'
document.body.innerHTML +=adminGroupId.id
// Create admin user instance. This is a single user with admin role
// represented by an asset. Is the asset representing admin1 user
// Create app asset with admin1, the umbrella asset for representing the app
const appAsset = {
ns: nameSpace,
name: nameSpace
}
const appMetadata = {
canLink: adminGroupId
}
const appId = (await createNewAsset(admin1, appAsset, appMetadata)).id
console.log('App: ' + appId)
}
```
The `createNewAsset` function looks like this
```js
async function createNewAsset(keypair, asset, metadata) {
let condition = driver.Transaction.makeEd25519Condition(keypair.publicKey,
true)
let output = driver.Transaction.makeOutput(condition)
output.public_keys = [keypair.publicKey]
const transaction = driver.Transaction.makeCreateTransaction(
asset,
metadata,
[output],
keypair.publicKey
)
const txSigned = driver.Transaction.signTransaction(transaction,
keypair.privateKey)
let tx
await conn.postTransaction(txSigned)
.then(() => conn.pollStatusAndFetchTransaction(txSigned.id))
.then(retrievedTx => {
tx = retrievedTx
})
return tx
}
```
You have just generated the admin type and app asset, so now you are able to create all of the other assets for this RBAC example, which are the users (including the admin one) and the tribe.
```js
function createUsers() {
const user1 = new driver.Ed25519Keypair()
const user2 = new driver.Ed25519Keypair()
const user3 = new driver.Ed25519Keypair()
const adminuser1Metadata = {
event: 'User Assigned',
date: new Date(),
timestamp: Date.now(),
publicKey: admin1.publicKey,
eventData: {
userType: 'admin'
}
}
// Admin user instance belongs to the AdminGroup
const adminUserId = (await createUser(admin1, adminGroupId, 'admin',
admin1.publicKey, adminuser1Metadata)).id
document.body.innerHTML ='<h3>Admin user asset created</h3>'
document.body.innerHTML +=adminUserId
// Tribes are user groups
const tribe1Id = (await createType('tribe1', appId, adminGroupId)).id
document.body.innerHTML ='<h3>Tribe 1 asset created</h3>'
document.body.innerHTML +=tribe1Id
const tribe2Id = (await createType('tribe2', appId, adminGroupId)).id
document.body.innerHTML ='<h3>Tribe 2 asset created</h3>'
document.body.innerHTML +=tribe2Id
// create user instances
const user1Metadata = {
event: 'User Assigned',
date: new Date(),
timestamp: Date.now(),
publicKey: admin1.publicKey,
eventData: {
userType: 'tribe1'
}
}
// Create the asset representing user1 with the admin1 keys.
// Add it to tribe 1
const user1AssetId = (await createUser(admin1, tribe1Id, 'tribe1',
user1.publicKey, user1Metadata)).id
document.body.innerHTML ='<h3>User 1 asset created</h3>'
document.body.innerHTML +=user1AssetId
// create user instances
const user2Metadata = {
event: 'User Assigned',
date: new Date(),
timestamp: Date.now(),
publicKey: admin1.publicKey,
eventData: {
userType: 'tribe2'
}
}
// user 2 added to tribe 2
// Is the asset representing user1
const user2AssetId = (await createUser(admin1, tribe2Id, 'tribe2',
user2.publicKey, user2Metadata)).id
document.body.innerHTML ='<h3>User 2 asset created</h3>'
document.body.innerHTML +=user2AssetId
const user3Metadata = {
event: 'User Assigned',
date: new Date(),
timestamp: Date.now(),
publicKey: admin1.publicKey,
eventData: {
userType: 'tribe1'
}
}
// user 3 added to tribe 1
const user3AssetId = (await createUser(admin1, tribe1Id, 'tribe1',
user3.publicKey, user3Metadata)).id
document.body.innerHTML ='<h3>User 3 asset created</h3>'
document.body.innerHTML +=user3AssetId
}
```
You have created the users, some of them belonging to tribe 1 and others to tribe 2. Now is time to give different permissions to the different tribes. For that you will create asset types for proposals and for votes.
```js
async function usersToTribes(){
// Non users
// Proposal: only tribe 1 users can create proposal
const proposalGroupId = (await createType('proposal', appId, tribe1Id)).id
console.log('ProposalGroup: ' + proposalGroupId)
// Vote: only tribe 2 users can create vote
const voteGroupId = (await createType('vote', appId, tribe2Id)).id
document.body.innerHTML ='<h3>Vote group asset created</h3>'
document.body.innerHTML +=voteGroupId
```
So now simply create proposals and votes from different users. You will see how just some users will be able to create proposals and some others will be able to vote.
```js
// create proposal by user 1 - should pass
const proposal1 = await createTypeInstance(user1, 'proposal',
proposalGroupId, { name: 'new proposal by user 1',
timestamp: Date.now() })
document.body.innerHTML ='<h3>Proposal group asset created</h3>'
document.body.innerHTML +=proposal1.id
// create vote by user 2 - should pass
const vote1 = await createTypeInstance(user2, 'vote', voteGroupId,
{ name: 'new vote by user 2', timestamp: Date.now() })
document.body.innerHTML ='<h3>Vote instance created</h3>'
document.body.innerHTML +=vote1.id
// create proposal by user 3 - should pass
const proposal2 = await createTypeInstance(user3, 'proposal',
proposalGroupId, { name: 'new proposal by user 3',
timestamp: Date.now() })
document.body.innerHTML ='<h3>Vote instance created</h3>'
document.body.innerHTML +=proposal2.id
// create vote by user 1 - should fail
const vote2 = await createTypeInstance(user1, 'vote',
voteGroupId, { name: 'new vote by user 1', timestamp: Date.now() })
document.body.innerHTML ='<h3>Vote instance could not be created</h3>'
document.body.innerHTML +=vote2.id
}
```
The concepts discussed in this guide can be found in detail on our [blog](https://blog.bigchaindb.com/role-based-access-control-for-bigchaindb-assets-b7cada491997).
The demo code is available in [GitHub](
https://github.com/bigchaindb/project-jannowitz/tree/master/rbac/demo).

View File

@ -0,0 +1,188 @@
---
layout: guide
title: "Tutorial: How to launch your own token on BigchainDB"
tagline: Learn how to use divisible assets in BigchainDB for token generating events
header: header-token.jpg
order: 3
learn: >
- How to use divisible assets on BigchainDB
- How assets in BigchainDB can represent tokens
- How tokens can be distributed to participants using TRANSFER transactions
- How various BigchainDB transactions can be combined together
---
Hi there! Welcome to our next tutorial about divisible assets. For this tutorial, we assume that you are familiar with the BigchainDB primitives (assets, inputs, outputs, transactions etc.). If you are not, familiarize yourself with the [Key concepts of BigchainDB](../key-concepts-of-bigchaindb/). We also assume that you have completed our [first tutorial](../tutorial-car-telemetry-app/).
# About token generating events
In the last 12 months we have witnessed exponential growth in token generating events. Many of them have been launched on Ethereum. Since we are experiencing rising interest in potential token launches on BigchainDB, this tutorial aims at showing a very simple approach on how to launch your own token on BigchainDB.
This tutorial just aims at illustrating the usage of one building block, namely divisible assets. An actual token launch is much more complex and requires other components which are not discussed here. Furthermore, BigchainDB is currently not yet ERC20 compatible.
{% include_relative _setup.md %}
# Usage of divisible assets to create tokens
In BigchainDB, a token generation can be represented as a divisible asset. A divisible asset is an asset that has a fixed number of sub-assets linked to it. This means that the create transaction contains more than that asset. The linked fixed sub-assets represent your tokens. When creating a divisible asset in BigchainDB, the number of the sub-assets (tokens) that you want to create needs to be specified in the beginning. That number represents your fixed total supply of tokens.
The code below illustrates how to create a divisible asset with 10 000 tokens associated to it.
```js
const nTokens = 10000
let tokensLeft
const tokenCreator = new BigchainDB
.Ed25519Keypair(bip39.mnemonicToSeed('seedPhrase').slice(0,32))
function tokenLaunch() {
// Construct a transaction payload
const tx = BigchainDB.Transaction.makeCreateTransaction({
token: 'TT (Tutorial Tokens)',
number_tokens: nTokens
},
// Metadata field, contains information about the transaction itself
// (can be `null` if not needed)
{
datetime: new Date().toString()
},
// Output: Divisible asset, include nTokens as parameter
[BigchainDB.Transaction.makeOutput(BigchainDB.Transaction
.makeEd25519Condition(tokenCreator.publicKey), nTokens.toString())],
tokenCreator.publicKey
)
// Sign the transaction with the private key of the token creator
const txSigned = BigchainDB.Transaction
.signTransaction(tx, tokenCreator.privateKey)
// Send the transaction off to BigchainDB
conn.postTransaction(txSigned)
.then(() => conn.pollStatusAndFetchTransaction(txSigned.id))
.then(res => {
tokensLeft = nTokens
document.body.innerHTML ='<h3>Transaction created</h3>';
// txSigned.id corresponds to the asset id of the tokens
document.body.innerHTML +=txSigned.id
})
}
```
With these commands, you have minted 10000 tokens. For that, give an extra parameter to the `makeOutput()` function. Pay attention to give the function a string instead of a plain number. With the `tokenCreator` keypair you indicate who will be the owner of the tokens. This could for instance be the foundation issuing the tokens. Once this transaction is accepted by BigchainDB, you update the value of the tokens left in the possession of the creator. Right now, all the tokens created are associated with the public key of the creator (`tokenCreater.publicKey`).
Now that the tokens have been minted, you can start distributing them to the owners.
# Distribution of tokens
Tokens can be transferred to an unlimited number of participants. In this example, you are now going to make a transfer transaction to transfer 200 tokens to a new user called John. For that, you first need to create a new user and then do the transfer. The code below shows that.
```js
const amountToSend = 200
const newUser = new BigchainDB
.Ed25519Keypair(bip39.mnemonicToSeed('newUserseedPhrase')
.slice(0, 32))
function transferTokens() {
// User who will receive the 200 tokens
const newUser = new BigchainDB.Ed25519Keypair()
// Search outputs of the transactions belonging the token creator
// False argument to retrieve unspent outputs
conn.listOutputs(tokenCreator.publicKey, 'false')
.then((txs) => {
// Just one transaction available with outputs not being spent by
// tokenCreator. Therefore, txs[0]
return conn.getTransaction(txs[0].transaction_id)
})
.then((txOutputs) => {
// Create transfer transaction
const createTranfer = BigchainDB.Transaction
.makeTransferTransaction(
[{
tx: txOutputs,
output_index: 0
}],
// Transaction output: Two outputs, because the whole input
// must be spent
[BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction
.makeEd25519Condition(tokenCreator.publicKey),
(tokensLeft - amountToSend).toString()),
BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction
.makeEd25519Condition(newUser.publicKey),
amountToSend)
],
// Metadata (optional)
{
transfer_to: 'john',
tokens_left: tokensLeft
}
)
// Sign the transaction with the tokenCreator key
const signedTransfer = BigchainDB.Transaction
.signTransaction(createTranfer, tokenCreator.privateKey)
return conn.postTransaction(signedTransfer)
})
.then((signedTransfer) => conn
.pollStatusAndFetchTransaction(signedTransfer.id))
.then(res => {
// Update tokensLeft
tokensLeft -= amountToSend
document.body.innerHTML += '<h3>Transfer transaction created</h3>'
document.body.innerHTML += res.id
})
}
```
You have now transferred 200 tokens to the user John. You could repeat the same with multiple other users.
With `listOutputs` using `false` as the second argument you retrieved all the outputs belonging to the user `tokenCreator`, that were not spent yet. There will just be one output that fulfills these characteristics, because when you transfer tokens to another user, you are spending this output and giving the ownership to the other user. Then, you queried for that transaction and made a transfer to John with it. Note however, that there is also a transaction back to `tokenCreator.publicKey`, as you need to 'give back change' due to BigchainDB's transaction model. It is designed in a way that all of the inputs have to be spent in a transaction. That means that if you send part of the `tokensLeft` (200 tokens) to John, you have to send the rest (9800 tokens) back to the `tokenCreator` to preserve that amount.
# Combination of different BigchainDB transactions
Imagine now that you have received several transactions of tokens and you want to combine all of the balances and transfer them to another user (e.g. your best friend, who keeps some tokens in escrow). In BigchainDB, this is possible as well. The code below illustrates how to do that.
```js
const amountToSend = 200
const bestFriend = new driver.Ed25519Keypair()
function combineTokens(transaction1, outputIndex1, transaction2, outputIndex2,
totalTokens) {
const combineTranfer = BigchainDB.Transaction.makeTransferTransaction(
[{
tx: transaction1,
output_index: outputIndex1
}, {
tx: transaction2,
output_index: outputIndex2
}],
// Output
[BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction.makeEd25519Condition(
bestFriend.publicKey),
(totalTokens).toString())], {
transfer_to: 'my best friend'
}
)
// Sign the transaction with the newUser key
const signedTransfer = BigchainDB.Transaction
.signTransaction(combineTranfer, newUser.privateKey)
return conn.postTransaction(signedTransfer)
}
```
You just made a transfer transaction combining two different transactions into one output. Note that the `totalTokens` quantity is a required variable. It is the sum of the tokens of the two outputs being spent. As you have seen before, if this quantity is not correct, the transaction will fail, as you literally need to spend all of the outputs in a transaction.
`transaction1` and `transaction2` can look like the transaction `createTranfer` that you did before. In that case, the `outputIndex1` and `outputIndex2` would be `0`.
Note that in our example, the supply of your tokens was fixed and cannot be changed anymore after creation. So, you would need to clearly define for yourself, how many tokens you will need. However, BigchainDB does offer the option of refillable, divisible assets that allow for a more dynamic token supply. You can learn more about that [here](https://github.com/bigchaindb/bigchaindb/issues/1741).
That's it! Now you know, how divisible assets in BigchainDB can be used as a potential building block for token launches. Of course, in practice a token distribution event is much more complex and requires other important building blocks like smart contracts etc. But, this tutorial showed you how divisible assets can play a part of that.

View File

@ -0,0 +1,20 @@
<header role="banner" class="header header--{{ page.url | replace: '/','' }} header--{{ page.layout }}"
{% if page.header %}
{% if page.path contains '_guides' %}
style="background-image:url('../{{ page.header }}')"
{% else %}
style="background-image:url('/assets/img/{{ page.header }}')"
{% endif %}
{% endif %}>
{% include menu-main.html %}
<div class="row">
<div class="header__content">
<h1 class="header__title">{{ page.title }}</h1>
{% if page.tagline %}
<h2 class="header__tagline">{{ page.tagline }}</h2>
{% endif %}
</div>
</div>
</header>

View File

@ -0,0 +1,24 @@
<section class="section section--guides">
<div class="row">
<header class="section-header">
<h1 class="section-title">Guides</h1>
<p class="section-description">Complete these guides to learn about how to create apps in BigchainDB.</p>
</header>
</div>
<div class="row">
{% assign guides = site.guides | sort: 'order' %}
{% for guide in guides limit: 3 %}
<article class="guide">
<a href="{{ guide.url }}" {% if guide.header %}style="background-image:url('/guides/{{ guide.header }}')" {% endif %}>
<h1 class="guide__title">{{ guide.title }}</h1>
<p class="guide__tagline">{{ guide.tagline }}</p>
</a>
</article>
{% endfor %}
</div>
<div class="row text-center">
<a class="btn btn-secondary" href="/guides/">All guides</a>
</div>
</section>

View File

@ -2,16 +2,7 @@
layout: base
---
<header role="banner" class="header" {% if page.image %}style="background-image:url('/assets/img/{{ page.image }}')"{% endif %}>
{% include menu-main.html %}
<div class="row">
<div class="header__content">
<h1 class="header__title">{{ page.title }}</h1>
</div>
</div>
</header>
{% include header.html %}
<section role="main" class="content content--page">

67
_src/_layouts/guide.html Normal file
View File

@ -0,0 +1,67 @@
---
layout: base
---
{% include header.html %}
<section role="main" class="content content--page content--guide">
<div class="row content--page--markdown">
{% if page.learn %}
<header class="section-header section-header--guide">
<div class="section-description">
<h2>You will learn</h2>
{{ page.learn | markdownify }}
</div>
</header>
{% endif %}
{{ content | toc }}
</div>
</section>
<section class="section section--guides-more">
<div class="row">
<header class="section-header">
<h1 class="section-title">More guides</h1>
</header>
</div>
<div class="row row--wide">
<div class="grid grid--full grid-small--half grid-medium--third grid--gutters">
{% for guide in site.guides limit: 6 %}
{% unless page.id == guide.id %}
<div class="grid__col">
<article class="guide">
<a href="{{ guide.url }}" {% if guide.header %}style="background-image:url('../{{ guide.header }}')"{% endif %}>
<h1 class="guide__title">{{ guide.title }}</h1>
</a>
</article>
</div>
{% endunless %}
{% endfor %}
</div>
</div>
<div class="row text-center">
<a class="btn btn-primary" href="/guides/">All guides</a>
</div>
</section>
<section class="section section--getstarted background--darker">
<div class="row row--wide">
<header class="section-header">
<h1 class="section-title">Get to know the BigchainDB universe</h1>
<div class="section-description">
<p>Explore drivers, tools & a lot more documentation.</p>
<a class="btn btn-primary" href="/getstarted/">Get started</a>
</div>
</header>
</div>
<aside class="starbase starbase--server">
<div class="row row--wide">
<figure class="starbase__image">
<img class="img--responsive" src="/assets/img/nosprite/starbase-server.svg" alt="Starbase" width="1111" height="343">
</figure>
</div>
</aside>
</section>

View File

@ -2,20 +2,7 @@
layout: base
---
<header role="banner" class="header" {% if page.header %}style="background-image:url('/assets/img/{{ page.header }}')"{% endif %}>
{% include menu-main.html %}
<div class="row">
<div class="header__content">
{% if page.tagline %}
<h1 class="header__tagline">{{ page.tagline }}
{% else %}
<h1 class="header__title">{{ page.title }}</h1>
{% endif %}
</div>
</div>
</header>
{% include header.html %}
<section role="main" class="content content--page">

View File

@ -7,16 +7,7 @@ cta:
button: Learn More
---
<header role="banner" class="header header--partner" {% if page.header %}style="background-image:url('/assets/img/{{ page.header }}')"{% endif %}>
{% include menu-main.html %}
<div class="row">
<hgroup class="header__content">
<h1 class="header__title">{{ page.title }}</h1>
</hgroup>
</div>
</header>
{% include header.html %}
<section role="main" class="section content content--page content--partner">

View File

@ -87,7 +87,6 @@ redirect_from:
from bigchaindb_driver import BigchainDB
from bigchaindb_driver.crypto import generate_keypair
bdb = BigchainDB(
'{{ site.bigchaindb_api_url }}',
headers={'app_id': 'Get credentials from testnet.bigchaindb.com',
@ -110,7 +109,6 @@ bdb.transactions.send(signed_tx)
```js
const driver = require('bigchaindb-driver')
const alice = new driver.Ed25519Keypair()
const conn = new driver.Connection(
'{{ site.bigchaindb_api_url }}/api/v1/',
@ -291,6 +289,15 @@ conn.postTransaction(txSigned)
<div class="row row--wide">
<div class="grid grid--full grid-small--fit grid--gutters">
<div class="grid__col">
<h2 class="docs__title">Guides</h2>
<ul class="docs__list">
{% for guide in site.guides limit: 8 %}
<li><a href="{{ guide.url }}">{{ guide.title }}</a></li>
{% endfor %}
</ul>
</div>
{% for category in content.docs.categories %}
<div class="grid__col">
@ -308,7 +315,8 @@ conn.postTransaction(txSigned)
</div>
<div class="row row--wide text-center">
<div class="docs__actions">
<a class="btn btn-secondary" href="https://docs.bigchaindb.com">{{ content.docs.button }}</a>
<a class="btn btn-primary" href="/guides/">{{ content.docs.button_guides }}</a>
<a class="btn btn-secondary" href="https://docs.bigchaindb.com">{{ content.docs.button_documentation }}</a>
</div>
</div>
</section>

40
_src/guides.html Normal file
View File

@ -0,0 +1,40 @@
---
layout: page
title: The Hitchhiker Guides to BigchainDB
tagline: "These guides explain you how to get started and build apps with BigchainDB"
image: share-image-guides.png
---
<section class="section section--guideslist">
<div class="row">
{% assign guides = site.guides | sort: 'order' %}
{% for guide in guides %}
<article class="guide">
<a href="{{ guide.url }}" {% if guide.header %}style="background-image:url('./{{ guide.header }}')" {% endif %}>
<h1 class="guide__title">{{ guide.title }}</h1>
<p class="guide__tagline">{{ guide.tagline }}</p>
</a>
</article>
{% endfor %}
</div>
</section>
<section class="section section--getstarted background--darker">
<div class="row row--wide">
<header class="section-header">
<h1 class="section-title">Get to know the BigchainDB universe</h1>
<div class="section-description">
<p>Explore drivers, tools & a lot more documentation.</p>
<a class="btn btn-primary" href="/getstarted/">Get started</a>
</div>
</header>
</div>
<aside class="starbase starbase--server">
<div class="row row--wide">
<figure class="starbase__image">
<img class="img--responsive" src="/assets/img/nosprite/starbase-server.svg" alt="Starbase" width="1111" height="343">
</figure>
</div>
</aside>
</section>

View File

@ -61,10 +61,10 @@ intro:
</div>
</section>
{% include sections/section-testimonials.html %}
{% include sections/section-cta-enterprise.html %}
{% include sections/section-guides.html %}
{% include sections/section-partners.html %}
{% include sections/section-cta-enterprise.html %}
{% include sections/section-blog.html %}

View File

@ -26,6 +26,7 @@
],
"dependencies": {
"bigchaindb-driver": "^3.2.0",
"clipboard": "^1.7.1",
"gumshoe": "github:cferdinandi/gumshoe",
"is-in-viewport": "^3.0.0",
"jquery": "^3.3.1",