Skip to content

Commit

Permalink
First!
Browse files Browse the repository at this point in the history
  • Loading branch information
marcopeereboom committed Jun 9, 2017
0 parents commit 1ad3245
Show file tree
Hide file tree
Showing 25 changed files with 4,758 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmd/dcrtime/dcrtime
dcrtimestored/dcrtimestored
vendor/
*~
*.pyc
*.sw?
*.orig
*.diff
16 changes: 16 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
ISC License

Copyright (c) 2013-2017 The btcsuite developers
Copyright (c) 2015-2017 The Decred developers

Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
157 changes: 157 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
dcrtime
=======

[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)

Decred anchored timestamp client and server.

The dcrtime stack as as follows:

```
+-------------------------+
| dcrtime |
+-------------------------+
|
~~~~~~~~ Internet ~~~~~~~~~
|
+-------------------------+
| dcrtimestored (proxy) |
+-------------------------+
|
~~~~~~~~~~ VPN ~~~~~~~~~~~~
|
+-------------------------+
| dcrtimestored (backend) |
+-------------------------+
|
+-------------------------+
| dcrwallet |
+-------------------------+
|
+-------------------------+
| dcrd |
+-------------------------+
```

## Components
* dcrtime - Reference client application
* dcrtimestored
- Proxy Mode: Forwards requests to the backend server.
- Backend mode: Manages timestamps and creates decred transaction that anchors transactions in the blockchain.

## Library and interfaces
* api/v1 - JSON REST API for dcrtime clients.
* cmd/dcrtime - Client reference implementation
* cmd/dcrtime_unflush - Debug backend tool to either delete the flush record or reset the chain timestamp.
* cmd/dcrtime_timestamp - Tool to convert between various timestamp formats.
* merkle - Merkle algorithm implementation.
* util - common used miscellaneous utility functions.

## Example setup

### Backend

This example dcrtimestored.conf connects to dcrwallet running on localhost using the testnet network.

```
wallethost=localhost
walletcert=../.dcrwallet/rpc.cert
walletpassphrase=MySikritPa$$w0ard
testnet=1
```

Start the store.
```
store-server$ dcrtimestored
07:36:09 2017-06-09 [INF] DCRT: Version : 0.1.0
07:36:09 2017-06-09 [INF] DCRT: Mode : Store
07:36:09 2017-06-09 [INF] DCRT: Network : testnet2
07:36:09 2017-06-09 [INF] DCRT: Home dir: /home/user/.dcrtimestored
07:36:09 2017-06-09 [INF] DCRT: Generating HTTPS keypair...
07:36:09 2017-06-09 [INF] DCRT: HTTPS keypair created...
07:36:09 2017-06-09 [INF] FSBE: Wallet: 127.0.0.1:19111
07:36:09 2017-06-09 [INF] DCRT: Start of day
07:36:09 2017-06-09 [INF] DCRT: Listen: :59152
07:58:03 2017-06-09 [INF] DCRT: Timestamp 203.0.113.4:44331 via 10.0.0.2:57126: rejected 20170609.120000 b1d080f4d09ea21a7b1872d87993079a84718f485de87d0327b6d1da922620e1
07:59:36 2017-06-09 [INF] DCRT: Timestamp 203.0.113.4:57138 via 10.0.0.2:32322: accepted 20170609.120000 8496855341883fdc90cc532f8304d1c46a60586fb15d99f07e41bb5ab19c79c6
08:00:10 2017-06-09 [INF] FSBE: flusher: directories 1 in 788.607578ms
08:15:29 2017-06-09 [INF] DCRT: Verify 203.0.113.4:39992 via 10.0.0.2:57144: Timestamps 0 Digests 1
08:16:36 2017-06-09 [INF] DCRT: Verify 204.0.113.4:57146 via 10.0.0.2:33881: Timestamps 0 Digests 1
08:16:36 2017-06-09 [INF] FSBE: Flushed anchor timestamp: 4172a560a7035c169c4da60cba2cb1fbac686bd01224e09a1a56ce5e6f31cff0 1497013614
```

### Proxy

dcrtimestored also has a proxy mode. It is activated by specifying the --storehost and --storecert options.
In this example, we assume the proxy has an internal interface with ip 10.0.0.2 that connects to storehost.example.com at 10.0.0.1.

```
proxy-server$ mkdir ~/.dcrtimestored
proxy-server$ scp storehost.example.com:/home/user/.dcrtimestored/https.cert ~/.dcrtimestored/dcrtimestored.cert
proxy-server$ dcrtimestored --testnet --storehost=storehost.example.com --storecert=~/.dcrtimestored/dcrtimestored.cert
07:50:59 2017-06-09 [WRN] DCRT: open /home/user/.dcrtimestored/dcrtimestored.conf: no such file or directory
07:50:59 2017-06-09 [INF] DCRT: Version : 0.1.0
07:50:59 2017-06-09 [INF] DCRT: Mode : Proxy
07:50:59 2017-06-09 [INF] DCRT: Network : testnet2
07:50:59 2017-06-09 [INF] DCRT: Home dir: /home/user/.dcrtimestored
07:50:59 2017-06-09 [INF] DCRT: Generating HTTPS keypair...
07:50:59 2017-06-09 [INF] DCRT: HTTPS keypair created...
07:50:59 2017-06-09 [INF] DCRT: Start of day
07:50:59 2017-06-09 [INF] DCRT: Listen: :59152
07:58:03 2017-06-09 [INF] DCRT: Timestamp 203.0.113.4:44331: b1d080f4d09ea21a7b1872d87993079a84718f485de87d0327b6d1da922620e1
07:59:36 2017-06-09 [INF] DCRT: Timestamp 203.0.113.4:57138: 8496855341883fdc90cc532f8304d1c46a60586fb15d99f07e41bb5ab19c79c6
08:15:29 2017-06-09 [INF] DCRT: Verify 203.0.113.4:39992: Timestamps 0 Digests 1
08:16:36 2017-06-09 [INF] DCRT: Verify 204.0.113.4:57146: Timestamps 0 Digests 1
```

Now we test the setup using dcrtime. Note that for this example one digest was already known to the system and one was not. You can spot the difference in the dcrtimestored trace byt the words "accepted" and "rejected". Accepted means the file digest was unknown to the store and could therefore be added. Rejected on the other hands means that said digest already exists and therefore can not be added again. A digest can only be queried once it has been added to the store.

Per the trace above we issue a known digest first:
```
$ dcrtime -v /bin/ls
b1d080f4d09ea21a7b1872d87993079a84718f485de87d0327b6d1da922620e1 Upload /bin/ls
b1d080f4d09ea21a7b1872d87993079a84718f485de87d0327b6d1da922620e1 Exists /bin/ls
Collection timestamp: 1497013200
```

And now we issue an unknown digest:
```
$ dcrtime -v myfile.txt
8496855341883fdc90cc532f8304d1c46a60586fb15d99f07e41bb5ab19c79c6 Upload myfile.txt
8496855341883fdc90cc532f8304d1c46a60586fb15d99f07e41bb5ab19c79c6 OK myfile.txt
Collection timestamp: 1497009600
```

In this example we wait a bit until the store hits its scheduled hourly flush regimen. This can be observed in the store trace.

And now let's ask about these digests:
```
$ dcrtime -v b1d080f4d09ea21a7b1872d87993079a84718f485de87d0327b6d1da922620e1
b1d080f4d09ea21a7b1872d87993079a84718f485de87d0327b6d1da922620e1 Verify
b1d080f4d09ea21a7b1872d87993079a84718f485de87d0327b6d1da922620e1 OK
Chain Timestamp: 1496430430
Merkle Root : 9788d5d7b85f2b68ec21d26e738dce6cdd367ee0ec58b53ad6bd4d46b0bc3018
TxID : 554b27c309ac9a8dab8ae261bb13dcfcdd351aa5f196322c112f04d106e000f3
```

The next digest was anchored but the store did not have the chain timestamp cached yet. This can be observed in the store trace; just look for "Flushed anchor".
```
$ dcrtime -v 8496855341883fdc90cc532f8304d1c46a60586fb15d99f07e41bb5ab19c79c6
8496855341883fdc90cc532f8304d1c46a60586fb15d99f07e41bb5ab19c79c6 Verify
8496855341883fdc90cc532f8304d1c46a60586fb15d99f07e41bb5ab19c79c6 OK
Chain Timestamp: 1497013614
Merkle Root : 8496855341883fdc90cc532f8304d1c46a60586fb15d99f07e41bb5ab19c79c6
TxID : 4172a560a7035c169c4da60cba2cb1fbac686bd01224e09a1a56ce5e6f31cff0
```

You can find the merkle root using block explorer. Surf to https://testnet.decred.org/tx/554b27c309ac9a8dab8ae261bb13dcfcdd351aa5f196322c112f04d106e000f3 and in the transaction you'll find an entry that is as follows:
```
OP_RETURN 9788d5d7b85f2b68ec21d26e738dce6cdd367ee0ec58b53ad6bd4d46b0bc3018
```
The astute reader noticed that this is the Merkle Root the dcrtime client returned.

Note that this example was run on a single machine but that the listen port bits were removed for clarity.

## License

dcrtime is licensed under the [copyfree](http://copyfree.org) ISC License.
94 changes: 94 additions & 0 deletions api/v1/v1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) 2017 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package v1

import (
"regexp"

"github.com/decred/dcrtime/merkle"
)

// XXX add a clamp to all batches

const (
TimestampRoute = "/v1/timestamp/" // Digests ingest
VerifyRoute = "/v1/verify/" // Multi verify ingest

// Result codes.
ResultOK = 0 // Operation completed succefully
ResultExistsError = 1 // Digest rejected because it exists
ResultDoesntExistError = 2 // Unknown timestamp or digest
)

var (
Result = map[int]string{
ResultOK: "OK",
ResultExistsError: "Exists",
ResultDoesntExistError: "Doesn't exist",
}

// Valid text representation of digests and timestamps.
RegexpSHA256 = regexp.MustCompile("[A-Fa-f0-9]{64}")
RegexpTimestamp = regexp.MustCompile("[0-9]{10}")
)

// Timestamp is used to ask the timestamp server to store a batch of digests.
// ID is user settable and can be used as a unique identifier by the client.
type Timestamp struct {
ID string `json:"id"`
Digests []string `json:"digests"`
}

// TimestampReply is returned by the timestamp server after storing the batch
// of digests. ID is copied from the originating Timestamp call and can be
// used by the client as a unique identifier. The ServerTimestamp indicates
// what collection the Digests belong to. Results contains individual result
// codes for each digest.
type TimestampReply struct {
ID string `json:"id"`
ServerTimestamp int64 `json:"servertimestamp"`
Digests []string `json:"digests"`
Results []int `json:"results"`
}

type Verify struct {
ID string `json:"id"`
Digests []string `json:"digests"`
Timestamps []int64 `json:"timestamps"`
}

type VerifyDigest struct {
Digest string `json:"digest"`
ServerTimestamp int64 `json:"servertimestamp"`
Result int `json:"result"`
ChainInformation ChainInformation `json:"chaininformation"`
}

// ChainTimestamp is zero if this digest collection is not anchored in the blockchain; it is however set to the block timestamp it was anchored in.
type VerifyTimestamp struct {
ServerTimestamp int64 `json:"servertimestamp"`
Result int `json:"result"`
CollectionInformation CollectionInformation `json:"collectioninformation"`
}

type VerifyReply struct {
ID string `json:"id"`
Digests []VerifyDigest `json:"digests"`
Timestamps []VerifyTimestamp `json:"timestamps"`
}

type ChainInformation struct {
ChainTimestamp int64 `json:"chaintimestamp"`
Transaction string `json:"transaction"`
MerkleRoot string `json:"merkleroot"`
MerklePath merkle.MerkleBranch `json:"merklepath"`
}

type CollectionInformation struct {
ChainTimestamp int64 `json:"chaintimestamp"`
Transaction string `json:"transaction"`
MerkleRoot string `json:"merkleroot"`
Digests []string `json:"digests"`
}
Loading

0 comments on commit 1ad3245

Please sign in to comment.