├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── circle.yml ├── package.json ├── src ├── common.js ├── index.js ├── resolver.js └── util.js └── test └── resolver.spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | ### module specific 2 | 3 | dist 4 | 5 | 6 | ### generic 7 | 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (http://nodejs.org/api/addons.html) 34 | build/Release 35 | 36 | # Dependency directories 37 | node_modules 38 | jspm_packages 39 | 40 | # Optional npm cache directory 41 | .npm 42 | 43 | # Optional REPL history 44 | .node_repl_history 45 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | matrix: 4 | include: 5 | - node_js: 4 6 | env: CXX=g++-4.8 7 | - node_js: 6 8 | env: 9 | - SAUCE=true 10 | - CXX=g++-4.8 11 | - node_js: stable 12 | env: CXX=g++-4.8 13 | 14 | # Make sure we have new NPM. 15 | before_install: 16 | - npm install -g npm 17 | 18 | script: 19 | - npm run lint 20 | - npm test 21 | - npm run coverage 22 | 23 | before_script: 24 | - export DISPLAY=:99.0 25 | - sh -e /etc/init.d/xvfb start 26 | 27 | after_success: 28 | - npm run coverage-publish 29 | 30 | addons: 31 | firefox: 'latest' 32 | apt: 33 | sources: 34 | - ubuntu-toolchain-r-test 35 | packages: 36 | - g++-4.8 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Protocol Labs Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecation Notice 2 | 3 | **This repo has been deprecated in favour of [js-ipld-ethereum](https://github.com/ipld/js-ipld-ethereum)** 4 | 5 | ---------------------------------------------------------------------- 6 | ---------------------------------------------------------------------- 7 | 8 | # js-ipld-eth-block 9 | 10 | [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) 11 | [![](https://img.shields.io/badge/project-IPLD-blue.svg?style=flat-square)](http://github.com/ipld/ipld) 12 | [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) 13 | 14 | > JavaScript Implementation of the IPLD format - Ethereum Block 15 | 16 | ## Install 17 | 18 | ```sh 19 | $ npm install ipld-eth-block 20 | ``` 21 | 22 | ## Usage 23 | 24 | TBD 25 | 26 | ## Maintainers 27 | 28 | - [@kumavis](https://github.com/kumavis) 29 | 30 | ## Contribute 31 | 32 | Please contribute! [Look at the issues](https://github.com/ipld/js-ipld-eth-block/issues)! 33 | 34 | Check out our [contributing document](https://github.com/ipld/ipld/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to IPLD are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). 35 | 36 | Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. 37 | 38 | ## License 39 | 40 | [MIT](LICENSE) © 2016 Protocol Labs Inc. 41 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | 2 | machine: 3 | node: 4 | version: stable 5 | 6 | dependencies: 7 | pre: 8 | - google-chrome --version 9 | - wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 10 | - sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 11 | - sudo apt-get update 12 | - sudo apt-get --only-upgrade install google-chrome-stable 13 | - google-chrome --version -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ipld-eth-block", 3 | "version": "2.3.0", 4 | "description": "JavaScript Implementation of the IPLD format - Ethereum Block", 5 | "main": "src/index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "cids": "~0.5.0", 11 | "ethereumjs-block": "^1.5.0", 12 | "multihashes": "~0.4.4" 13 | }, 14 | "devDependencies": { 15 | "aegir": "^11.0.0", 16 | "async": "^2.1.5", 17 | "chai": "^3.5.0", 18 | "dirty-chai": "^1.2.2", 19 | "ipfs-block": "~0.6.0", 20 | "multihashing-async": "^0.4.4" 21 | }, 22 | "scripts": { 23 | "test": "aegir-test", 24 | "test:browser": "aegir-test --env browser", 25 | "test:node": "aegir-test --env node", 26 | "lint": "aegir-lint", 27 | "release": "aegir-release", 28 | "release-minor": "aegir-release --type minor", 29 | "release-major": "aegir-release --type major", 30 | "build": "aegir-build", 31 | "coverage": "aegir-coverage", 32 | "coverage-publish": "aegir-coverage publish" 33 | }, 34 | "repository": { 35 | "type": "git", 36 | "url": "git+https://github.com/ipld/js-ipld-eth-block.git" 37 | }, 38 | "author": "", 39 | "license": "MIT", 40 | "bugs": { 41 | "url": "https://github.com/ipld/js-ipld-eth-block/issues" 42 | }, 43 | "homepage": "https://github.com/ipld/js-ipld-eth-block#readme", 44 | "contributors": [ 45 | "David Dias ", 46 | "Richard Littauer ", 47 | "kumavis " 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /src/common.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const CID = require('cids') 4 | const multihashes = require('multihashes') 5 | 6 | module.exports = { 7 | cidForHash: cidForHash 8 | } 9 | 10 | function cidForHash (codec, rawhash) { 11 | var multihash = multihashes.encode(rawhash, 'keccak-256') 12 | return new CID(1, codec, multihash) 13 | } 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.util = require('./util.js') 4 | exports.resolver = require('./resolver.js') 5 | -------------------------------------------------------------------------------- /src/resolver.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const util = require('./util') 4 | const cidForHash = require('./common').cidForHash 5 | 6 | exports = module.exports 7 | 8 | exports.multicodec = 'eth-block' 9 | 10 | /* 11 | * resolve: receives a path and a block and returns the value on path, 12 | * throw if not possible. `block` is an IPFS Block instance (contains data + key) 13 | */ 14 | exports.resolve = (block, path, callback) => { 15 | util.deserialize(block.data, (err, ethBlock) => { 16 | if (err) return callback(err) 17 | exports.resolveFromObject(ethBlock, path, callback) 18 | }) 19 | } 20 | 21 | exports.resolveFromObject = (ethBlock, path, callback) => { 22 | let result 23 | 24 | // root 25 | if (!path || path === '/') { 26 | result = { value: ethBlock, remainderPath: '' } 27 | return callback(null, result) 28 | } 29 | 30 | // check tree results 31 | let pathParts = path.split('/') 32 | let firstPart = pathParts.shift() 33 | let remainderPath = pathParts.join('/') 34 | 35 | exports.treeFromObject(ethBlock, {}, (err, paths) => { 36 | if (err) return callback(err) 37 | let treeResult = paths.find(child => child.path === firstPart) 38 | if (!treeResult) { 39 | let err = new Error('Path not found ("' + firstPart + '").') 40 | return callback(err) 41 | } 42 | 43 | result = { 44 | value: treeResult.value, 45 | remainderPath: remainderPath 46 | } 47 | return callback(null, result) 48 | }) 49 | } 50 | 51 | /* 52 | * tree: returns a flattened array with paths: values of the project. options 53 | * are option (i.e. nestness) 54 | */ 55 | 56 | exports.tree = (block, options, callback) => { 57 | // parse arguments 58 | if (typeof options === 'function') { 59 | callback = options 60 | options = undefined 61 | } 62 | if (!options) { 63 | options = {} 64 | } 65 | 66 | util.deserialize(block.data, (err, ethBlock) => { 67 | if (err) return callback(err) 68 | exports.treeFromObject(ethBlock, options, callback) 69 | }) 70 | } 71 | 72 | exports.treeFromObject = (ethBlock, options, callback) => { 73 | const paths = [] 74 | 75 | // external links 76 | paths.push({ 77 | path: 'parent', 78 | value: { '/': cidForHash('eth-block', ethBlock.parentHash).toBaseEncodedString() } 79 | }) 80 | paths.push({ 81 | path: 'ommers', 82 | value: { '/': cidForHash('eth-block-list', ethBlock.uncleHash).toBaseEncodedString() } 83 | }) 84 | paths.push({ 85 | path: 'transactions', 86 | value: { '/': cidForHash('eth-tx-trie', ethBlock.transactionsTrie).toBaseEncodedString() } 87 | }) 88 | paths.push({ 89 | path: 'transactionReceipts', 90 | value: { '/': cidForHash('eth-tx-receipt-trie', ethBlock.receiptTrie).toBaseEncodedString() } 91 | }) 92 | paths.push({ 93 | path: 'state', 94 | value: { '/': cidForHash('eth-state-trie', ethBlock.stateRoot).toBaseEncodedString() } 95 | }) 96 | 97 | // external links as data 98 | paths.push({ 99 | path: 'parentHash', 100 | value: ethBlock.parentHash 101 | }) 102 | paths.push({ 103 | path: 'ommerHash', 104 | value: ethBlock.uncleHash 105 | }) 106 | paths.push({ 107 | path: 'transactionTrieRoot', 108 | value: ethBlock.transactionsTrie 109 | }) 110 | paths.push({ 111 | path: 'transactionReceiptTrieRoot', 112 | value: ethBlock.receiptTrie 113 | }) 114 | paths.push({ 115 | path: 'stateRoot', 116 | value: ethBlock.stateRoot 117 | }) 118 | 119 | // internal data 120 | paths.push({ 121 | path: 'authorAddress', 122 | value: ethBlock.coinbase 123 | }) 124 | paths.push({ 125 | path: 'bloom', 126 | value: ethBlock.bloom 127 | }) 128 | paths.push({ 129 | path: 'difficulty', 130 | value: ethBlock.difficulty 131 | }) 132 | paths.push({ 133 | path: 'number', 134 | value: ethBlock.number 135 | }) 136 | paths.push({ 137 | path: 'gasLimit', 138 | value: ethBlock.gasLimit 139 | }) 140 | paths.push({ 141 | path: 'gasUsed', 142 | value: ethBlock.gasUsed 143 | }) 144 | paths.push({ 145 | path: 'timestamp', 146 | value: ethBlock.timestamp 147 | }) 148 | paths.push({ 149 | path: 'extraData', 150 | value: ethBlock.extraData 151 | }) 152 | paths.push({ 153 | path: 'mixHash', 154 | value: ethBlock.mixHash 155 | }) 156 | paths.push({ 157 | path: 'nonce', 158 | value: ethBlock.nonce 159 | }) 160 | 161 | callback(null, paths) 162 | } 163 | 164 | exports.isLink = (block, path, callback) => { 165 | exports.resolve(block, path, (err, result) => { 166 | if (err) { 167 | return callback(err) 168 | } 169 | 170 | if (result.remainderPath.length > 0) { 171 | return callback(new Error('path out of scope')) 172 | } 173 | 174 | if (typeof result.value === 'object' && result.value['/']) { 175 | callback(null, result.value) 176 | } else { 177 | callback(null, false) 178 | } 179 | }) 180 | } 181 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const EthBlockHeader = require('ethereumjs-block/header') 4 | const cidForHash = require('./common').cidForHash 5 | 6 | exports.deserialize = function (data, callback) { 7 | let deserialized 8 | try { 9 | deserialized = new EthBlockHeader(data) 10 | } catch (err) { 11 | return callback(err) 12 | } 13 | callback(null, deserialized) 14 | } 15 | 16 | exports.serialize = function (blockHeader, callback) { 17 | let serialized 18 | try { 19 | serialized = blockHeader.serialize() 20 | } catch (err) { 21 | return callback(err) 22 | } 23 | callback(null, serialized) 24 | } 25 | 26 | exports.cid = function (blockHeader, callback) { 27 | let cid 28 | try { 29 | cid = cidForHash('eth-block', blockHeader.hash()) 30 | } catch (err) { 31 | return callback(err) 32 | } 33 | callback(null, cid) 34 | } 35 | -------------------------------------------------------------------------------- /test/resolver.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 'use strict' 3 | 4 | const chai = require('chai') 5 | chai.use(require('dirty-chai')) 6 | const expect = chai.expect 7 | const CID = require('cids') 8 | const IpfsBlock = require('ipfs-block') 9 | const EthBlockHeader = require('ethereumjs-block/header') 10 | const multihashing = require('multihashing-async') 11 | const waterfall = require('async/waterfall') 12 | 13 | const ipldEthBlock = require('../src') 14 | const resolver = ipldEthBlock.resolver 15 | 16 | describe('IPLD format resolver (local)', () => { 17 | let testIpfsBlock 18 | let testData = { 19 | // 12345678901234567890123456789012 20 | parentHash: new Buffer('0100000000000000000000000000000000000000000000000000000000000000', 'hex'), 21 | uncleHash: new Buffer('0200000000000000000000000000000000000000000000000000000000000000', 'hex'), 22 | coinbase: new Buffer('0300000000000000000000000000000000000000', 'hex'), 23 | stateRoot: new Buffer('0400000000000000000000000000000000000000000000000000000000000000', 'hex'), 24 | transactionsTrie: new Buffer('0500000000000000000000000000000000000000000000000000000000000000', 'hex'), 25 | receiptTrie: new Buffer('0600000000000000000000000000000000000000000000000000000000000000', 'hex'), 26 | // bloom: new Buffer('07000000000000000000000000000000', 'hex'), 27 | difficulty: new Buffer('0800000000000000000000000000000000000000000000000000000000000000', 'hex'), 28 | number: new Buffer('0900000000000000000000000000000000000000000000000000000000000000', 'hex'), 29 | gasLimit: new Buffer('1000000000000000000000000000000000000000000000000000000000000000', 'hex'), 30 | gasUsed: new Buffer('1100000000000000000000000000000000000000000000000000000000000000', 'hex'), 31 | timestamp: new Buffer('1200000000000000000000000000000000000000000000000000000000000000', 'hex'), 32 | extraData: new Buffer('1300000000000000000000000000000000000000000000000000000000000000', 'hex'), 33 | mixHash: new Buffer('1400000000000000000000000000000000000000000000000000000000000000', 'hex'), 34 | nonce: new Buffer('1500000000000000000000000000000000000000000000000000000000000000', 'hex') 35 | } 36 | 37 | before((done) => { 38 | const testEthBlock = new EthBlockHeader(testData) 39 | waterfall([ 40 | (cb) => ipldEthBlock.util.serialize(testEthBlock, cb), 41 | (serialized, cb) => multihashing(serialized, 'keccak-256', (err, hash) => { 42 | if (err) { 43 | return cb(err) 44 | } 45 | testIpfsBlock = new IpfsBlock(serialized, new CID(hash)) 46 | cb() 47 | }) 48 | ], done) 49 | }) 50 | 51 | it('multicodec is eth-block', () => { 52 | expect(resolver.multicodec).to.equal('eth-block') 53 | }) 54 | 55 | it('can parse the cid', (done) => { 56 | const testEthBlock = new EthBlockHeader(testData) 57 | ipldEthBlock.util.cid(testEthBlock, (err, cid) => { 58 | expect(err).not.to.exist() 59 | let encodedCid = cid.toBaseEncodedString() 60 | let reconstructedCid = new CID(encodedCid) 61 | expect(cid.version).to.equal(reconstructedCid.version) 62 | expect(cid.codec).to.equal(reconstructedCid.codec) 63 | expect(cid.multihash.toString('hex')).to.equal(reconstructedCid.multihash.toString('hex')) 64 | done() 65 | }) 66 | }) 67 | 68 | describe('resolver.resolve', () => { 69 | it('path within scope', () => { 70 | resolver.resolve(testIpfsBlock, 'number', (err, result) => { 71 | expect(err).not.to.exist() 72 | expect(result.value.toString('hex')).to.equal(testData.number.toString('hex')) 73 | }) 74 | }) 75 | }) 76 | 77 | it('resolver.tree', () => { 78 | resolver.tree(testIpfsBlock, (err, paths) => { 79 | expect(err).not.to.exist() 80 | expect(Array.isArray(paths)).to.eql(true) 81 | }) 82 | }) 83 | }) 84 | --------------------------------------------------------------------------------