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

car-telemetry-app structure changed

This commit is contained in:
manolodewiner 2017-12-19 13:22:00 +01:00
parent e5ffb9c5de
commit 9b5e987394
2 changed files with 116 additions and 321 deletions

View File

@ -1,202 +0,0 @@
---
layout: guide
title: "Tutorial: How to create a digital track of a piece of art"
tagline: Build a digital track of a famous paint that you own
header: header-car.jpg
order: 2
learn: >
- How BigchainDB can be used to record dynamic parameters of an asset
- 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 asset to create `TRANSFER` transactions to change the ownership of an asset in BigchainDB
---
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 object
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.
Let's get started!
{% include_relative _setup.md %}
# Create 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. Alice will be the owner of the car, and she will be the only one able to update the mileage of the car. Using her public key, anyone can also verify that Alice is the creator of the car.
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
After having generated a key pair, you can create transactions in BigchainDB, so you can start registering your paint in BigchainDB. This corresponds to an asset creation. In our case, an asset will represent an object in real life, namely a paint. This asset will live in BigchainDB forever and there is no possibility to delete it. This is the immutability property of blockchain technology.
The first thing needed is the definition of the asset field that represents the car. It has a JSON format:
```js
const paint = {
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:
```js
function createPaint() {
// Construct a transaction payload
const txCreateCar = BigchainDB.Transaction.makeCreateTransaction(
// Asset field
{
...paint,
},
// Metadata field, contains information about the transaction itself
// (can be `null` if not needed)
// Initialize the mileage with 0 km
{
datetime: new Date().toString(),
location: 'Madrid',
value: {
value_eur: '2500000€',
value_btc: '220',
}
},
// 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 paint signs the transaction
const txSigned = BigchainDB.Transaction.signTransaction(txCreateCar,
alice.privateKey)
// Send the transaction off to BigchainDB
conn.postTransaction(txSigned)
// Check the status of the transaction every 0.5 seconds.
.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 car
})
}
```
Now you have digitally registered the car on BigchainDB, respectively in our case on IPDB. `txSigned.id` is an id that uniquely identifies your asset. Note that the metadata field is used to record values along with the transaction, as every transaction can have new metadata.
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 an asset on BigchainDB
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 (Alice) as beneficiary, but with new metadata in the transaction. So, technically, Alice is transferring the car to herself and just adding additional, new information to that transaction.
Before creating the transfer transaction, you need to search for the last transaction with the asset id, as you will transfer this specific last transaction:
```js
conn.listTransactions(assetId)
.then((txList) => {
// If just one transaction
if (txList.length <= 1) {
return txList
}
const inputTransactions = []
txList.forEach((tx) =>
tx.inputs.forEach(input => {
// Create transactions have null fulfills by definition
if (input.fulfills) {
// Push all of the transfer transactions
inputTransactions.push(input.fulfills.transaction_id)
}
})
)
// In our case there should be just one input that has not been spent
// with the assetId
return txList.filter((tx) => inputTransactions.indexOf(tx.id) === -1)
})
```
The `listTransactions` method of BigchainDB retrieves all of the create and transfer transactions with a specific asset id. Then, we check for the inputs that have not been spent yet. This indicates the last transaction. In this tutorial, we are just working with one input and one output for each transaction, so there should be just one input that has not been spent yet, namely the one belonging to the last transaction.
Based on that, we can now create the transfer transaction:
```js
function transferOnwership(assetId, newOwner) {
// Update the paint with a new
// First, we query for the asset paint that we created
conn.listTransactions(assetId)
.then((txList) => {
if (txList.length <= 1) {
return txList
}
const inputTransactions = []
txList.forEach((tx) =>
tx.inputs.forEach(input => {
if (input.fulfills) {
inputTransactions.push(input.fulfills.transaction_id)
}
})
)
// In our case there should be just one input not spend with the a
// ssetId
return txList.filter((tx) =>
inputTransactions.indexOf(tx.id) === -1)
})
.then((tx) => {
// As there is just one input
return conn.getTransaction(tx[0].id)
})
.then((txCreated) => {
const createTranfer = BigchainDB.Transaction.
makeTransferTransaction(
txCreated, {
datetime: new Date().toString(),
location: 'Amsterdam',
value: {
value_eur: '2500000€',
value_btc: '200',
}
}, [BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction.makeEd25519Condition(
newOwner.publicKey))],
0
)
// Sign with the owner of the paint as she was the creator of the
// paint
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 is transferring the ownership of the Meninas to anybody else. Furthermore, the input being spent is 0, as there is just one input.
So, finally you sign the transaction and send it to BigchainDB. You have now updated your asset and it is now not anymore you who will be able to transfer again the paint.
That's it, we have created a paint asset.
Congratulations! You have successfully finished your first BigchainDB tutorial.

View File

@ -30,19 +30,60 @@ Let's get started!
# Create 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. Alice will be the owner of the car, and she will be the only one able to update the mileage of the car. Using her public key, anyone can also verify that Alice is the creator of the car.
In BigchainDB, users are represented as a private and public key pair. In our case, a key pair for Alice will be created.
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.
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 order to create different assets in BigchainDB we will use the Decentralized Identifiers 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.(https://w3c-ccg.github.io/did-spec/)
So in this case, each object in the real world as the car, the telemetry box, the GPS device, etc, will be represented by a DID. Each object will have a a tag or cryptochip containing a securely hidden private key.
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 developers.ipdb.io',
app_key: 'Get one from developers.ipdb.io'
}
)
this.entity = entity
}
}
```
So as each object has a keypair, is possible to create a DID from each object. The objects are "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. As in 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")
```
# Digital registration of an asset on BigchainDB
After having generated a key pair, you can create transactions in BigchainDB, so you can start registering your car in BigchainDB. This corresponds to an asset creation. In our case, an asset will represent an object in real life, namely a car. This asset will live in BigchainDB forever and there is no possibility to delete it. This is the immutability property of blockchain technology.
After having generated key pairs, you can create assets in BigchainDB. First 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.
The first thing needed is the definition of the asset field that represents the car. It has a JSON format:
These assets will live in BigchainDB forever and there is no possibility to delete it. This is the immutability property of blockchain technology.
You can start creating the car asset, so the first thing needed is the definition of the asset field that represents the car. It has a JSON format:
```js
const vehicle = {
@ -55,135 +96,91 @@ const vehicle = {
}
```
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:
As a next step, you need to generate a `CREATE` transaction that represents the user DID in BigchainDB. The user is a self-owned identity, so you will use Alice keypair to create the `userDID`
```js
function createCar() {
// Construct a transaction payload
const txCreate = BigchainDB.Transaction.makeCreateTransaction(
// Asset field
{
...vehicle,
datetime: new Date().toString()
},
// Metadata field, contains information about the transaction itself
// (can be `null` if not needed)
// Initialize the mileage with 0 km
{
mileage: 0,
units: 'km'
},
// Output. For this case we create a simple Ed25519 condition
[BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction.makeEd25519Condition(carOwner.publicKey))],
// Issuers
carOwner.publicKey
)
// The owner of the car signs the transaction
const txSigned = BigchainDB.Transaction.signTransaction(txCreate, carOwner.privateKey)
// Send the transaction off to BigchainDB
conn.postTransaction(txSigned)
// Check the status of the transaction every 0.5 seconds.
.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 car
})
}
```
Now you have digitally registered the car on BigchainDB, respectively in our case on IPDB. `txSigned.id` is an id that uniquely identifies your asset. Note that the metadata field is used to record the mileage, which is currently set to 0.
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).
We will use this feature to update the mileage of the car. Note that by using `carOwner.publicKey` in the output of the create transaction, you have established that Alice will be the only person able to update the metadata value, respectively a `TRANSFER` transaction for this asset. That's because the usage of this output as an input in a separate transaction will require a signature with Alices private key.
# Update of an asset on BigchainDB
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 (Alice) as beneficiary, but with new metadata in the transaction. So, technically, Alice is transferring the car to herself and just adding additional, new information to that transaction.
Before creating the transfer transaction, you need to search for the last transaction with the asset id, as you will transfer this specific last transaction:
```js
conn.listTransactions(assetId)
.then((txList) => {
// If just one transaction
if (txList.length <= 1) {
return txList
userDID.myModel.create({
keypair: alice,
data: {
name: 'Alice',
bithday: '03/08/1910'
}
const inputTransactions = []
txList.forEach((tx) =>
tx.inputs.forEach(input => {
// Create transactions have null fulfills by definition
if (input.fulfills) {
// Push all of the transfer transactions
inputTransactions.push(input.fulfills.transaction_id)
}
})
)
// In our case there should be just one input that has not been spent with the assetId
return txList.filter((tx) => inputTransactions.indexOf(tx.id) === -1)
}).then(asset => {
userDID.id = 'did:' + asset.id
document.body.innerHTML +='<h3>Transaction created</h3>'
document.body.innerHTML +=asset.id
})
```
The `listTransactions` method of BigchainDB retrieves all of the create and transfer transactions with a specific asset id. Then, we check for the inputs that have not been spent yet. This indicates the last transaction. In this tutorial, we are just working with one input and one output for each transaction, so there should be just one input that has not been spent yet, namely the one belonging to the last transaction.
Based on that, we can now create the transfer transaction:
As you can see, inheriting the Orm class 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.
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
function updateMileage(assetId, mileageValue) {
// Update the car with a new mileageValue of e.g. 55km.
// First, we query for the asset car that we created
conn.listTransactions(assetId)
.then((txList) => {
if (txList.length <= 1) {
return txList
}
const inputTransactions = []
txList.forEach((tx) =>
tx.inputs.forEach(input => {
if (input.fulfills) {
inputTransactions.push(input.fulfills.transaction_id)
}
})
)
// In our case there should be just one input not spend with the assetId
return txList.filter((tx) => inputTransactions.indexOf(tx.id) === -1)
})
.then((tx) => {
// As there is just one input
return conn.getTransaction(tx[0].id)
})
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
})
```
.then((txCreated) => {
const createTranfer = BigchainDB.Transaction.makeTransferTransaction(
txCreated, {
mileage: txCreated.metadata.mileage + mileageValue,
units: 'km'
}, [BigchainDB.Transaction.makeOutput(
BigchainDB.Transaction.makeEd25519Condition(carOwner.publicKey))],
0
)
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
// Sign with the owner of the car as she was the creator of the car
const signedTransfer = BigchainDB.Transaction.signTransaction(createTranfer, carOwner.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
```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 IPDB.
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
})
}
```
Once you have the last transaction, you create the transfer transaction with the new metadata value of e.g. 55 km.
Note again that in the output of this transfer transaction we have `carOwner.publicKey`. This shows that Alice is not transferring the ownership of the car to anybody else, because she is still the only person who can use that output as an input in another transaction. Furthermore, the input being spent is 0, as there is just one input.
So, finally you sign the transaction and send it to BigchainDB. You have now updated your asset and it is now recorded that your car has driven a distance of 55 km.
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.