diff --git a/README.md b/README.md index c54a555cb5..4830d93032 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20 Ethereum Go Client © 2014 Jeffrey Wilcke. -Current state: Proof of Concept 0.7 +Current state: Proof of Concept 0.8 Ethereum is currently in its testing phase. diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 7efee31e78..b238522820 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -25,13 +25,14 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" ) const ( ClientIdentifier = "Ethereum(G)" - Version = "0.7.11" + Version = "0.8.0" ) var clilogger = logger.NewLogger("CLI") @@ -48,35 +49,26 @@ func main() { // precedence: code-internal flag default < config file < environment variables < command line Init() // parsing command line - // If the difftool option is selected ignore all other log output - if DiffTool || Dump { - LogLevel = 0 - } - utils.InitConfig(VmType, ConfigFile, Datadir, "ETH") - ethutil.Config.Diff = DiffTool - ethutil.Config.DiffType = DiffType - utils.InitDataDir(Datadir) - - utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile) - - db := utils.NewDatabase() - err := utils.DBSanityCheck(db) + ethereum, err := eth.New(ð.Config{ + Name: ClientIdentifier, + Version: Version, + KeyStore: KeyStore, + DataDir: Datadir, + LogFile: LogFile, + LogLevel: LogLevel, + Identifier: Identifier, + MaxPeers: MaxPeer, + Port: OutboundPort, + NATType: PMPGateway, + PMPGateway: PMPGateway, + KeyRing: KeyRing, + }) if err != nil { - fmt.Println(err) - - os.Exit(1) + clilogger.Fatalln(err) } - - keyManager := utils.NewKeyManager(KeyStore, Datadir, db) - - // create, import, export keys - utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) - - clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier, string(keyManager.PublicKey())) - - ethereum := utils.NewEthereum(db, clientIdentity, keyManager, utils.NatType(NatType, PMPGateway), OutboundPort, MaxPeer) + utils.KeyTasks(ethereum.KeyManager(), KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) if Dump { var block *types.Block @@ -103,11 +95,7 @@ func main() { fmt.Println(block) - os.Exit(0) - } - - if ShowGenesis { - utils.ShowGenesis(ethereum) + return } if StartMining { diff --git a/cmd/ethtest/LICENSE b/cmd/ethtest/LICENSE deleted file mode 100644 index 0f187b8736..0000000000 --- a/cmd/ethtest/LICENSE +++ /dev/null @@ -1,14 +0,0 @@ -This file is part of ethereum.js. - -ethereum.js is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -ethereum.js is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with ethereum.js. If not, see . \ No newline at end of file diff --git a/cmd/ethtest/README.md b/cmd/ethtest/README.md deleted file mode 100644 index 865b62c6b1..0000000000 --- a/cmd/ethtest/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# Ethereum JavaScript API - -This is the Ethereum compatible JavaScript API using `Promise`s -which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js - -[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url] - - - -## Installation - -### Node.js - - npm install ethereum.js - -### For browser -Bower - - bower install ethereum.js - -Component - - component install ethereum/ethereum.js - -* Include `ethereum.min.js` in your html file. -* Include [es6-promise](https://github.com/jakearchibald/es6-promise) or another ES6-Shim if your browser doesn't support ECMAScript 6. - -## Usage -Require the library: - - var web3 = require('web3'); - -Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider) - - var web3.setProvider(new web3.providers.WebSocketProvider('ws://localhost:40404/eth')); - -There you go, now you can use it: - -``` -web3.eth.coinbase.then(function(result){ - console.log(result); - return web3.eth.balanceAt(result); -}).then(function(balance){ - console.log(web3.toDecimal(balance)); -}).catch(function(err){ - console.log(err); -}); -``` - - -For another example see `example/index.html`. - -## Building - -* `gulp build` - - -### Testing - -**Please note this repo is in it's early stage.** - -If you'd like to run a WebSocket ethereum node check out -[go-ethereum](https://github.com/ethereum/go-ethereum). - -To install ethereum and spawn a node: - -``` -go get github.com/ethereum/go-ethereum/ethereum -ethereum -ws -loglevel=4 -``` - -[npm-image]: https://badge.fury.io/js/ethereum.js.png -[npm-url]: https://npmjs.org/package/ethereum.js -[travis-image]: https://travis-ci.org/ethereum/ethereum.js.svg -[travis-url]: https://travis-ci.org/ethereum/ethereum.js -[dep-image]: https://david-dm.org/ethereum/ethereum.js.svg -[dep-url]: https://david-dm.org/ethereum/ethereum.js -[dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg -[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies \ No newline at end of file diff --git a/cmd/ethtest/bower.json b/cmd/ethtest/bower.json deleted file mode 100644 index cedae9023d..0000000000 --- a/cmd/ethtest/bower.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "ethereum.js", - "namespace": "ethereum", - "version": "0.0.3", - "description": "Ethereum Compatible JavaScript API", - "main": ["./dist/ethereum.js", "./dist/ethereum.min.js"], - "dependencies": { - "es6-promise": "#master" - }, - "repository": { - "type": "git", - "url": "https://github.com/ethereum/ethereum.js.git" - }, - "homepage": "https://github.com/ethereum/ethereum.js", - "bugs": { - "url": "https://github.com/ethereum/ethereum.js/issues" - }, - "keywords": [ - "ethereum", - "javascript", - "API" - ], - "authors": [ - { - "name": "Marek Kotewicz", - "email": "marek@ethdev.com", - "homepage": "https://github.com/debris" - }, - { - "name": "Marian Oancea", - "email": "marian@ethdev.com", - "homepage": "https://github.com/cubedro" - } - ], - "license": "LGPL-3.0", - "ignore": [ - "example", - "lib", - "node_modules", - "package.json", - ".bowerrc", - ".editorconfig", - ".gitignore", - ".jshintrc", - ".npmignore", - ".travis.yml", - "gulpfile.js", - "index.js", - "**/*.txt" - ] -} \ No newline at end of file diff --git a/cmd/ethtest/dist/ethereum.js b/cmd/ethtest/dist/ethereum.js deleted file mode 100644 index b64c15b9e2..0000000000 --- a/cmd/ethtest/dist/ethereum.js +++ /dev/null @@ -1,20 +0,0 @@ -require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oi&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ir&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},toDecimal:function(t){return parseInt(t,16)},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(t){return new a(t,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(t){return new a(t,i)}},on:function(t,e,n){return void 0===g._events[t]&&(g._events[t]={}),g._events[t][e]=n,this},off:function(t,e){return void 0!==g._events[t]&&delete g._events[t][e],this},trigger:function(t,e,n){var r,o=g._events[t];o&&o[e]&&(r=o[e])(n)}};f(g.eth,u()),v(g.eth,c()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,p()),i={changed:"shh_changed"},f(i,d()),s=function(){var t,e;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,t=this,(e=function(){t.provider&&t.provider.poll&&t.polls.forEach(function(e){e.data._id=t.id,t.id++,t.provider.poll(e.data,e.id)}),setTimeout(e,12e3)})()},s.prototype.send=function(t,e){t._id=this.id,e&&(g._callbacks[t._id]=e),t.args=t.args||[],this.id++,void 0!==this.provider?this.provider.send(t):(console.warn("provider is not set"),this.queued.push(t))},s.prototype.set=function(t){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=t,this.ready=!0},s.prototype.sendQueued=function(){for(var t=0;this.queued.length;t++)this.send(this.queued[t])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(t,e){this.provider&&this.provider.poll&&this.polls.push({data:t,id:e})},s.prototype.stopPolling=function(t){var e,n;for(e=this.polls.length;e--;)n=this.polls[e],n.id===t&&this.polls.splice(e,1)},g.provider=new s,g.setProvider=function(t){t.onmessage=r,g.provider.set(t),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(t,e){this.impl=e,this.callbacks=[];var n=this;this.promise=e.newFilter(t),this.promise.then(function(t){n.id=t,g.on(e.changed,t,n.trigger.bind(n)),g.provider.startPolling({call:e.changed,args:[t]},t)})},a.prototype.arrived=function(t){this.changed(t)},a.prototype.changed=function(t){var e=this;this.promise.then(function(){e.callbacks.push(t)})},a.prototype.trigger=function(t){for(var e=0;e - - - - - - - - -

contract

-
-
- -
- -
- - - diff --git a/cmd/ethtest/example/index.html b/cmd/ethtest/example/index.html deleted file mode 100644 index d0bf094ef2..0000000000 --- a/cmd/ethtest/example/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - -

coinbase balance

- -
-
-
-
- - - diff --git a/cmd/ethtest/example/node-app.js b/cmd/ethtest/example/node-app.js deleted file mode 100644 index f63fa9115f..0000000000 --- a/cmd/ethtest/example/node-app.js +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env node - -require('es6-promise').polyfill(); - -var web3 = require("../index.js"); - -web3.setProvider(new web3.providers.HttpRpcProvider('http://localhost:8080')); - -web3.eth.coinbase.then(function(result){ - console.log(result); - return web3.eth.balanceAt(result); -}).then(function(balance){ - console.log(web3.toDecimal(balance)); -}).catch(function(err){ - console.log(err); -}); \ No newline at end of file diff --git a/cmd/ethtest/gulpfile.js b/cmd/ethtest/gulpfile.js deleted file mode 100644 index 9e0717d8b1..0000000000 --- a/cmd/ethtest/gulpfile.js +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -var path = require('path'); - -var del = require('del'); -var gulp = require('gulp'); -var browserify = require('browserify'); -var jshint = require('gulp-jshint'); -var uglify = require('gulp-uglify'); -var rename = require('gulp-rename'); -var envify = require('envify/custom'); -var unreach = require('unreachable-branch-transform'); -var source = require('vinyl-source-stream'); -var exorcist = require('exorcist'); -var bower = require('bower'); - -var DEST = './dist/'; - -var build = function(src, dst) { - return browserify({ - debug: true, - insert_global_vars: false, - detectGlobals: false, - bundleExternal: false - }) - .require('./' + src + '.js', {expose: 'web3'}) - .add('./' + src + '.js') - .transform('envify', { - NODE_ENV: 'build' - }) - .transform('unreachable-branch-transform') - .transform('uglifyify', { - mangle: false, - compress: { - dead_code: false, - conditionals: true, - unused: false, - hoist_funs: true, - hoist_vars: true, - negate_iife: false - }, - beautify: true, - warnings: true - }) - .bundle() - .pipe(exorcist(path.join( DEST, dst + '.js.map'))) - .pipe(source(dst + '.js')) - .pipe(gulp.dest( DEST )); -}; - -var buildDev = function(src, dst) { - return browserify({ - debug: true, - insert_global_vars: false, - detectGlobals: false, - bundleExternal: false - }) - .require('./' + src + '.js', {expose: 'web3'}) - .add('./' + src + '.js') - .transform('envify', { - NODE_ENV: 'build' - }) - .transform('unreachable-branch-transform') - .bundle() - .pipe(exorcist(path.join( DEST, dst + '.js.map'))) - .pipe(source(dst + '.js')) - .pipe(gulp.dest( DEST )); -}; - -var uglifyFile = function(file) { - return gulp.src( DEST + file + '.js') - .pipe(uglify()) - .pipe(rename(file + '.min.js')) - .pipe(gulp.dest( DEST )); -}; - -gulp.task('bower', function(cb){ - bower.commands.install().on('end', function (installed){ - console.log(installed); - cb(); - }); -}); - -gulp.task('lint', function(){ - return gulp.src(['./*.js', './lib/*.js']) - .pipe(jshint()) - .pipe(jshint.reporter('default')); -}); - -gulp.task('clean', ['lint'], function(cb) { - del([ DEST ], cb); -}); - -gulp.task('build', ['clean'], function () { - return build('index', 'ethereum'); -}); - -gulp.task('buildQt', ['clean'], function () { - return build('index_qt', 'ethereum'); -}); - -gulp.task('buildDev', ['clean'], function () { - return buildDev('index', 'ethereum'); -}); - -gulp.task('uglify', ['build'], function(){ - return uglifyFile('ethereum'); -}); - -gulp.task('uglifyQt', ['buildQt'], function () { - return uglifyFile('ethereum'); -}); - -gulp.task('watch', function() { - gulp.watch(['./lib/*.js'], ['lint', 'prepare', 'build']); -}); - -gulp.task('default', ['bower', 'lint', 'build', 'uglify']); -gulp.task('qt', ['bower', 'lint', 'buildQt', 'uglifyQt']); -gulp.task('dev', ['bower', 'lint', 'buildDev']); - diff --git a/cmd/ethtest/index.js b/cmd/ethtest/index.js deleted file mode 100644 index c2de7e735e..0000000000 --- a/cmd/ethtest/index.js +++ /dev/null @@ -1,8 +0,0 @@ -var web3 = require('./lib/main'); -web3.providers.WebSocketProvider = require('./lib/websocket'); -web3.providers.HttpRpcProvider = require('./lib/httprpc'); -web3.providers.QtProvider = require('./lib/qt'); -web3.providers.AutoProvider = require('./lib/autoprovider'); -web3.contract = require('./lib/contract'); - -module.exports = web3; diff --git a/cmd/ethtest/index_qt.js b/cmd/ethtest/index_qt.js deleted file mode 100644 index d5e47597e4..0000000000 --- a/cmd/ethtest/index_qt.js +++ /dev/null @@ -1,5 +0,0 @@ -var web3 = require('./lib/main'); -web3.providers.QtProvider = require('./lib/qt'); -web3.contract = require('./lib/contract'); - -module.exports = web3; diff --git a/cmd/ethtest/lib/abi.js b/cmd/ethtest/lib/abi.js deleted file mode 100644 index 2cff503d38..0000000000 --- a/cmd/ethtest/lib/abi.js +++ /dev/null @@ -1,218 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file abi.js - * @authors: - * Marek Kotewicz - * Gav Wood - * @date 2014 - */ - -// TODO: make these be actually accurate instead of falling back onto JS's doubles. -var hexToDec = function (hex) { - return parseInt(hex, 16).toString(); -}; - -var decToHex = function (dec) { - return parseInt(dec).toString(16); -}; - -var findIndex = function (array, callback) { - var end = false; - var i = 0; - for (; i < array.length && !end; i++) { - end = callback(array[i]); - } - return end ? i - 1 : -1; -}; - -var findMethodIndex = function (json, methodName) { - return findIndex(json, function (method) { - return method.name === methodName; - }); -}; - -var padLeft = function (string, chars) { - return Array(chars - string.length + 1).join("0") + string; -}; - -var setupInputTypes = function () { - var prefixedType = function (prefix) { - return function (type, value) { - var expected = prefix; - if (type.indexOf(expected) !== 0) { - return false; - } - - var padding = parseInt(type.slice(expected.length)) / 8; - if (typeof value === "number") - value = value.toString(16); - else if (value.indexOf('0x') === 0) - value = value.substr(2); - else - value = (+value).toString(16); - return padLeft(value, padding * 2); - }; - }; - - var namedType = function (name, padding, formatter) { - return function (type, value) { - if (type !== name) { - return false; - } - - return padLeft(formatter ? formatter(value) : value, padding * 2); - }; - }; - - var formatBool = function (value) { - return value ? '0x1' : '0x0'; - }; - - return [ - prefixedType('uint'), - prefixedType('int'), - prefixedType('hash'), - namedType('address', 20), - namedType('bool', 1, formatBool), - ]; -}; - -var inputTypes = setupInputTypes(); - -var toAbiInput = function (json, methodName, params) { - var bytes = ""; - var index = findMethodIndex(json, methodName); - - if (index === -1) { - return; - } - - bytes = "0x" + padLeft(index.toString(16), 2); - var method = json[index]; - - for (var i = 0; i < method.inputs.length; i++) { - var found = false; - for (var j = 0; j < inputTypes.length && !found; j++) { - found = inputTypes[j](method.inputs[i].type, params[i]); - } - if (!found) { - console.error('unsupported json type: ' + method.inputs[i].type); - } - bytes += found; - } - return bytes; -}; - -var setupOutputTypes = function () { - var prefixedType = function (prefix) { - return function (type) { - var expected = prefix; - if (type.indexOf(expected) !== 0) { - return -1; - } - - var padding = parseInt(type.slice(expected.length)) / 8; - return padding * 2; - }; - }; - - var namedType = function (name, padding) { - return function (type) { - return name === type ? padding * 2 : -1; - }; - }; - - var formatInt = function (value) { - return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value); - }; - - var formatHash = function (value) { - return "0x" + value; - }; - - var formatBool = function (value) { - return value === '1' ? true : false; - }; - - return [ - { padding: prefixedType('uint'), format: formatInt }, - { padding: prefixedType('int'), format: formatInt }, - { padding: prefixedType('hash'), format: formatHash }, - { padding: namedType('address', 20) }, - { padding: namedType('bool', 1), format: formatBool } - ]; -}; - -var outputTypes = setupOutputTypes(); - -var fromAbiOutput = function (json, methodName, output) { - var index = findMethodIndex(json, methodName); - - if (index === -1) { - return; - } - - output = output.slice(2); - - var result = []; - var method = json[index]; - for (var i = 0; i < method.outputs.length; i++) { - var padding = -1; - for (var j = 0; j < outputTypes.length && padding === -1; j++) { - padding = outputTypes[j].padding(method.outputs[i].type); - } - - if (padding === -1) { - // not found output parsing - continue; - } - var res = output.slice(0, padding); - var formatter = outputTypes[j - 1].format; - result.push(formatter ? formatter(res) : ("0x" + res)); - output = output.slice(padding); - } - - return result; -}; - -var inputParser = function (json) { - var parser = {}; - json.forEach(function (method) { - parser[method.name] = function () { - var params = Array.prototype.slice.call(arguments); - return toAbiInput(json, method.name, params); - }; - }); - - return parser; -}; - -var outputParser = function (json) { - var parser = {}; - json.forEach(function (method) { - parser[method.name] = function (output) { - return fromAbiOutput(json, method.name, output); - }; - }); - - return parser; -}; - -module.exports = { - inputParser: inputParser, - outputParser: outputParser -}; diff --git a/cmd/ethtest/lib/autoprovider.js b/cmd/ethtest/lib/autoprovider.js deleted file mode 100644 index bfbc3ab6e1..0000000000 --- a/cmd/ethtest/lib/autoprovider.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file autoprovider.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * @date 2014 - */ - -/* - * @brief if qt object is available, uses QtProvider, - * if not tries to connect over websockets - * if it fails, it uses HttpRpcProvider - */ - -// TODO: work out which of the following two lines it is supposed to be... -//if (process.env.NODE_ENV !== 'build') { -if ("build" !== 'build') {/* - var WebSocket = require('ws'); // jshint ignore:line - var web3 = require('./main.js'); // jshint ignore:line -*/} - -var AutoProvider = function (userOptions) { - if (web3.haveProvider()) { - return; - } - - // before we determine what provider we are, we have to cache request - this.sendQueue = []; - this.onmessageQueue = []; - - if (navigator.qt) { - this.provider = new web3.providers.QtProvider(); - return; - } - - userOptions = userOptions || {}; - var options = { - httprpc: userOptions.httprpc || 'http://localhost:8080', - websockets: userOptions.websockets || 'ws://localhost:40404/eth' - }; - - var self = this; - var closeWithSuccess = function (success) { - ws.close(); - if (success) { - self.provider = new web3.providers.WebSocketProvider(options.websockets); - } else { - self.provider = new web3.providers.HttpRpcProvider(options.httprpc); - self.poll = self.provider.poll.bind(self.provider); - } - self.sendQueue.forEach(function (payload) { - self.provider(payload); - }); - self.onmessageQueue.forEach(function (handler) { - self.provider.onmessage = handler; - }); - }; - - var ws = new WebSocket(options.websockets); - - ws.onopen = function() { - closeWithSuccess(true); - }; - - ws.onerror = function() { - closeWithSuccess(false); - }; -}; - -AutoProvider.prototype.send = function (payload) { - if (this.provider) { - this.provider.send(payload); - return; - } - this.sendQueue.push(payload); -}; - -Object.defineProperty(AutoProvider.prototype, 'onmessage', { - set: function (handler) { - if (this.provider) { - this.provider.onmessage = handler; - return; - } - this.onmessageQueue.push(handler); - } -}); - -module.exports = AutoProvider; diff --git a/cmd/ethtest/lib/contract.js b/cmd/ethtest/lib/contract.js deleted file mode 100644 index 17b077484b..0000000000 --- a/cmd/ethtest/lib/contract.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file contract.js - * @authors: - * Marek Kotewicz - * @date 2014 - */ - -// TODO: work out which of the following two lines it is supposed to be... -//if (process.env.NODE_ENV !== 'build') { -if ("build" !== 'build') {/* - var web3 = require('./web3'); // jshint ignore:line -*/} -var abi = require('./abi'); - -var contract = function (address, desc) { - var inputParser = abi.inputParser(desc); - var outputParser = abi.outputParser(desc); - - var contract = {}; - - desc.forEach(function (method) { - contract[method.name] = function () { - var params = Array.prototype.slice.call(arguments); - var parsed = inputParser[method.name].apply(null, params); - - var onSuccess = function (result) { - return outputParser[method.name](result); - }; - - return { - call: function (extra) { - extra = extra || {}; - extra.to = address; - extra.data = parsed; - return web3.eth.call(extra).then(onSuccess); - }, - transact: function (extra) { - extra = extra || {}; - extra.to = address; - extra.data = parsed; - return web3.eth.transact(extra).then(onSuccess); - } - }; - }; - }); - - return contract; -}; - -module.exports = contract; diff --git a/cmd/ethtest/lib/httprpc.js b/cmd/ethtest/lib/httprpc.js deleted file mode 100644 index ee6b5c3070..0000000000 --- a/cmd/ethtest/lib/httprpc.js +++ /dev/null @@ -1,95 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file httprpc.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * @date 2014 - */ - -// TODO: work out which of the following two lines it is supposed to be... -//if (process.env.NODE_ENV !== 'build') { -if ("build" !== "build") {/* - var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line -*/} - -var HttpRpcProvider = function (host) { - this.handlers = []; - this.host = host; -}; - -function formatJsonRpcObject(object) { - return { - jsonrpc: '2.0', - method: object.call, - params: object.args, - id: object._id - }; -} - -function formatJsonRpcMessage(message) { - var object = JSON.parse(message); - - return { - _id: object.id, - data: object.result, - error: object.error - }; -} - -HttpRpcProvider.prototype.sendRequest = function (payload, cb) { - var data = formatJsonRpcObject(payload); - - var request = new XMLHttpRequest(); - request.open("POST", this.host, true); - request.send(JSON.stringify(data)); - request.onreadystatechange = function () { - if (request.readyState === 4 && cb) { - cb(request); - } - }; -}; - -HttpRpcProvider.prototype.send = function (payload) { - var self = this; - this.sendRequest(payload, function (request) { - self.handlers.forEach(function (handler) { - handler.call(self, formatJsonRpcMessage(request.responseText)); - }); - }); -}; - -HttpRpcProvider.prototype.poll = function (payload, id) { - var self = this; - this.sendRequest(payload, function (request) { - var parsed = JSON.parse(request.responseText); - if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) { - return; - } - self.handlers.forEach(function (handler) { - handler.call(self, {_event: payload.call, _id: id, data: parsed.result}); - }); - }); -}; - -Object.defineProperty(HttpRpcProvider.prototype, "onmessage", { - set: function (handler) { - this.handlers.push(handler); - } -}); - -module.exports = HttpRpcProvider; diff --git a/cmd/ethtest/lib/main.js b/cmd/ethtest/lib/main.js deleted file mode 100644 index 59c60cfa81..0000000000 --- a/cmd/ethtest/lib/main.js +++ /dev/null @@ -1,494 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file main.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * Marian Oancea - * Gav Wood - * @date 2014 - */ - -function flattenPromise (obj) { - if (obj instanceof Promise) { - return Promise.resolve(obj); - } - - if (obj instanceof Array) { - return new Promise(function (resolve) { - var promises = obj.map(function (o) { - return flattenPromise(o); - }); - - return Promise.all(promises).then(function (res) { - for (var i = 0; i < obj.length; i++) { - obj[i] = res[i]; - } - resolve(obj); - }); - }); - } - - if (obj instanceof Object) { - return new Promise(function (resolve) { - var keys = Object.keys(obj); - var promises = keys.map(function (key) { - return flattenPromise(obj[key]); - }); - - return Promise.all(promises).then(function (res) { - for (var i = 0; i < keys.length; i++) { - obj[keys[i]] = res[i]; - } - resolve(obj); - }); - }); - } - - return Promise.resolve(obj); -} - -var web3Methods = function () { - return [ - { name: 'sha3', call: 'web3_sha3' } - ]; -}; - -var ethMethods = function () { - var blockCall = function (args) { - return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; - }; - - var transactionCall = function (args) { - return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; - }; - - var uncleCall = function (args) { - return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; - }; - - var methods = [ - { name: 'balanceAt', call: 'eth_balanceAt' }, - { name: 'stateAt', call: 'eth_stateAt' }, - { name: 'storageAt', call: 'eth_storageAt' }, - { name: 'countAt', call: 'eth_countAt'}, - { name: 'codeAt', call: 'eth_codeAt' }, - { name: 'transact', call: 'eth_transact' }, - { name: 'call', call: 'eth_call' }, - { name: 'block', call: blockCall }, - { name: 'transaction', call: transactionCall }, - { name: 'uncle', call: uncleCall }, - { name: 'compilers', call: 'eth_compilers' }, - { name: 'lll', call: 'eth_lll' }, - { name: 'solidity', call: 'eth_solidity' }, - { name: 'serpent', call: 'eth_serpent' }, - { name: 'logs', call: 'eth_logs' } - ]; - return methods; -}; - -var ethProperties = function () { - return [ - { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, - { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, - { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, - { name: 'gasPrice', getter: 'eth_gasPrice' }, - { name: 'account', getter: 'eth_account' }, - { name: 'accounts', getter: 'eth_accounts' }, - { name: 'peerCount', getter: 'eth_peerCount' }, - { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, - { name: 'number', getter: 'eth_number'} - ]; -}; - -var dbMethods = function () { - return [ - { name: 'put', call: 'db_put' }, - { name: 'get', call: 'db_get' }, - { name: 'putString', call: 'db_putString' }, - { name: 'getString', call: 'db_getString' } - ]; -}; - -var shhMethods = function () { - return [ - { name: 'post', call: 'shh_post' }, - { name: 'newIdentity', call: 'shh_newIdentity' }, - { name: 'haveIdentity', call: 'shh_haveIdentity' }, - { name: 'newGroup', call: 'shh_newGroup' }, - { name: 'addToGroup', call: 'shh_addToGroup' } - ]; -}; - -var ethWatchMethods = function () { - var newFilter = function (args) { - return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; - }; - - return [ - { name: 'newFilter', call: newFilter }, - { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, - { name: 'getMessages', call: 'eth_filterLogs' } - ]; -}; - -var shhWatchMethods = function () { - return [ - { name: 'newFilter', call: 'shh_newFilter' }, - { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, - { name: 'getMessage', call: 'shh_getMessages' } - ]; -}; - -var setupMethods = function (obj, methods) { - methods.forEach(function (method) { - obj[method.name] = function () { - return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) { - var call = typeof method.call === "function" ? method.call(args) : method.call; - return {call: call, args: args}; - }).then(function (request) { - return new Promise(function (resolve, reject) { - web3.provider.send(request, function (err, result) { - if (!err) { - resolve(result); - return; - } - reject(err); - }); - }); - }).catch(function(err) { - console.error(err); - }); - }; - }); -}; - -var setupProperties = function (obj, properties) { - properties.forEach(function (property) { - var proto = {}; - proto.get = function () { - return new Promise(function(resolve, reject) { - web3.provider.send({call: property.getter}, function(err, result) { - if (!err) { - resolve(result); - return; - } - reject(err); - }); - }); - }; - if (property.setter) { - proto.set = function (val) { - return flattenPromise([val]).then(function (args) { - return new Promise(function (resolve) { - web3.provider.send({call: property.setter, args: args}, function (err, result) { - if (!err) { - resolve(result); - return; - } - reject(err); - }); - }); - }).catch(function (err) { - console.error(err); - }); - }; - } - Object.defineProperty(obj, property.name, proto); - }); -}; - -// TODO: import from a dependency, don't duplicate. -var hexToDec = function (hex) { - return parseInt(hex, 16).toString(); -}; - -var decToHex = function (dec) { - return parseInt(dec).toString(16); -}; - - -var web3 = { - _callbacks: {}, - _events: {}, - providers: {}, - - toAscii: function(hex) { - // Find termination - var str = ""; - var i = 0, l = hex.length; - if (hex.substring(0, 2) === '0x') - i = 2; - for(; i < l; i+=2) { - var code = hex.charCodeAt(i); - if(code === 0) { - break; - } - - str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); - } - - return str; - }, - - fromAscii: function(str, pad) { - pad = pad === undefined ? 32 : pad; - var hex = this.toHex(str); - while(hex.length < pad*2) - hex += "00"; - return "0x" + hex; - }, - - toDecimal: function (val) { - return hexToDec(val.substring(2)); - }, - - fromDecimal: function (val) { - return "0x" + decToHex(val); - }, - - toEth: function(str) { - var val = typeof str === "string" ? str.indexOf('0x') == 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; - var unit = 0; - var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ]; - while (val > 3000 && unit < units.length - 1) - { - val /= 1000; - unit++; - } - var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); - while (true) { - var o = s; - s = s.replace(/(\d)(\d\d\d[\.\,])/, function($0, $1, $2) { return $1 + ',' + $2; }); - if (o == s) - break; - } - return s + ' ' + units[unit]; - }, - - eth: { - prototype: Object(), // jshint ignore:line - watch: function (params) { - return new Filter(params, ethWatch); - } - }, - - db: { - prototype: Object() // jshint ignore:line - }, - - shh: { - prototype: Object(), // jshint ignore:line - watch: function (params) { - return new Filter(params, shhWatch); - } - }, - - on: function(event, id, cb) { - if(web3._events[event] === undefined) { - web3._events[event] = {}; - } - - web3._events[event][id] = cb; - return this; - }, - - off: function(event, id) { - if(web3._events[event] !== undefined) { - delete web3._events[event][id]; - } - - return this; - }, - - trigger: function(event, id, data) { - var callbacks = web3._events[event]; - if (!callbacks || !callbacks[id]) { - return; - } - var cb = callbacks[id]; - cb(data); - } -}; - -setupMethods(web3, web3Methods()); -setupMethods(web3.eth, ethMethods()); -setupProperties(web3.eth, ethProperties()); -setupMethods(web3.db, dbMethods()); -setupMethods(web3.shh, shhMethods()); - -var ethWatch = { - changed: 'eth_changed' -}; -setupMethods(ethWatch, ethWatchMethods()); -var shhWatch = { - changed: 'shh_changed' -}; -setupMethods(shhWatch, shhWatchMethods()); - -var ProviderManager = function() { - this.queued = []; - this.polls = []; - this.ready = false; - this.provider = undefined; - this.id = 1; - - var self = this; - var poll = function () { - if (self.provider && self.provider.poll) { - self.polls.forEach(function (data) { - data.data._id = self.id; - self.id++; - self.provider.poll(data.data, data.id); - }); - } - setTimeout(poll, 12000); - }; - poll(); -}; - -ProviderManager.prototype.send = function(data, cb) { - data._id = this.id; - if (cb) { - web3._callbacks[data._id] = cb; - } - - data.args = data.args || []; - this.id++; - - if(this.provider !== undefined) { - this.provider.send(data); - } else { - console.warn("provider is not set"); - this.queued.push(data); - } -}; - -ProviderManager.prototype.set = function(provider) { - if(this.provider !== undefined && this.provider.unload !== undefined) { - this.provider.unload(); - } - - this.provider = provider; - this.ready = true; -}; - -ProviderManager.prototype.sendQueued = function() { - for(var i = 0; this.queued.length; i++) { - // Resend - this.send(this.queued[i]); - } -}; - -ProviderManager.prototype.installed = function() { - return this.provider !== undefined; -}; - -ProviderManager.prototype.startPolling = function (data, pollId) { - if (!this.provider || !this.provider.poll) { - return; - } - this.polls.push({data: data, id: pollId}); -}; - -ProviderManager.prototype.stopPolling = function (pollId) { - for (var i = this.polls.length; i--;) { - var poll = this.polls[i]; - if (poll.id === pollId) { - this.polls.splice(i, 1); - } - } -}; - -web3.provider = new ProviderManager(); - -web3.setProvider = function(provider) { - provider.onmessage = messageHandler; - web3.provider.set(provider); - web3.provider.sendQueued(); -}; - -web3.haveProvider = function() { - return !!web3.provider.provider; -}; - -var Filter = function(options, impl) { - this.impl = impl; - this.callbacks = []; - - var self = this; - this.promise = impl.newFilter(options); - this.promise.then(function (id) { - self.id = id; - web3.on(impl.changed, id, self.trigger.bind(self)); - web3.provider.startPolling({call: impl.changed, args: [id]}, id); - }); -}; - -Filter.prototype.arrived = function(callback) { - this.changed(callback); -}; - -Filter.prototype.changed = function(callback) { - var self = this; - this.promise.then(function(id) { - self.callbacks.push(callback); - }); -}; - -Filter.prototype.trigger = function(messages) { - for(var i = 0; i < this.callbacks.length; i++) { - this.callbacks[i].call(this, messages); - } -}; - -Filter.prototype.uninstall = function() { - var self = this; - this.promise.then(function (id) { - self.impl.uninstallFilter(id); - web3.provider.stopPolling(id); - web3.off(impl.changed, id); - }); -}; - -Filter.prototype.messages = function() { - var self = this; - return this.promise.then(function (id) { - return self.impl.getMessages(id); - }); -}; - -Filter.prototype.logs = function () { - return this.messages(); -}; - -function messageHandler(data) { - if(data._event !== undefined) { - web3.trigger(data._event, data._id, data.data); - return; - } - - if(data._id) { - var cb = web3._callbacks[data._id]; - if (cb) { - cb.call(this, data.error, data.data); - delete web3._callbacks[data._id]; - } - } -} - -module.exports = web3; diff --git a/cmd/ethtest/lib/qt.js b/cmd/ethtest/lib/qt.js deleted file mode 100644 index f022395476..0000000000 --- a/cmd/ethtest/lib/qt.js +++ /dev/null @@ -1,45 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file qt.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * @date 2014 - */ - -var QtProvider = function() { - this.handlers = []; - - var self = this; - navigator.qt.onmessage = function (message) { - self.handlers.forEach(function (handler) { - handler.call(self, JSON.parse(message.data)); - }); - }; -}; - -QtProvider.prototype.send = function(payload) { - navigator.qt.postMessage(JSON.stringify(payload)); -}; - -Object.defineProperty(QtProvider.prototype, "onmessage", { - set: function(handler) { - this.handlers.push(handler); - } -}); - -module.exports = QtProvider; diff --git a/cmd/ethtest/lib/websocket.js b/cmd/ethtest/lib/websocket.js deleted file mode 100644 index 24a0725313..0000000000 --- a/cmd/ethtest/lib/websocket.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file websocket.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * Marian Oancea - * @date 2014 - */ - -// TODO: work out which of the following two lines it is supposed to be... -//if (process.env.NODE_ENV !== 'build') { -if ("build" !== "build") {/* - var WebSocket = require('ws'); // jshint ignore:line -*/} - -var WebSocketProvider = function(host) { - // onmessage handlers - this.handlers = []; - // queue will be filled with messages if send is invoked before the ws is ready - this.queued = []; - this.ready = false; - - this.ws = new WebSocket(host); - - var self = this; - this.ws.onmessage = function(event) { - for(var i = 0; i < self.handlers.length; i++) { - self.handlers[i].call(self, JSON.parse(event.data), event); - } - }; - - this.ws.onopen = function() { - self.ready = true; - - for(var i = 0; i < self.queued.length; i++) { - // Resend - self.send(self.queued[i]); - } - }; -}; - -WebSocketProvider.prototype.send = function(payload) { - if(this.ready) { - var data = JSON.stringify(payload); - - this.ws.send(data); - } else { - this.queued.push(payload); - } -}; - -WebSocketProvider.prototype.onMessage = function(handler) { - this.handlers.push(handler); -}; - -WebSocketProvider.prototype.unload = function() { - this.ws.close(); -}; -Object.defineProperty(WebSocketProvider.prototype, "onmessage", { - set: function(provider) { this.onMessage(provider); } -}); - -module.exports = WebSocketProvider; diff --git a/cmd/ethtest/package.json b/cmd/ethtest/package.json deleted file mode 100644 index 24141ea2e4..0000000000 --- a/cmd/ethtest/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "ethereum.js", - "namespace": "ethereum", - "version": "0.0.5", - "description": "Ethereum Compatible JavaScript API", - "main": "./index.js", - "directories": { - "lib": "./lib" - }, - "dependencies": { - "es6-promise": "*", - "ws": "*", - "xmlhttprequest": "*" - }, - "devDependencies": { - "bower": ">=1.3.0", - "browserify": ">=6.0", - "del": ">=0.1.1", - "envify": "^3.0.0", - "exorcist": "^0.1.6", - "gulp": ">=3.4.0", - "gulp-jshint": ">=1.5.0", - "gulp-rename": ">=1.2.0", - "gulp-uglify": ">=1.0.0", - "jshint": ">=2.5.0", - "uglifyify": "^2.6.0", - "unreachable-branch-transform": "^0.1.0", - "vinyl-source-stream": "^1.0.0" - }, - "scripts": { - "build": "gulp", - "watch": "gulp watch", - "lint": "gulp lint" - }, - "repository": { - "type": "git", - "url": "https://github.com/ethereum/ethereum.js.git" - }, - "homepage": "https://github.com/ethereum/ethereum.js", - "bugs": { - "url": "https://github.com/ethereum/ethereum.js/issues" - }, - "keywords": [ - "ethereum", - "javascript", - "API" - ], - "author": "ethdev.com", - "authors": [ - { - "name": "Jeffery Wilcke", - "email": "jeff@ethdev.com", - "url": "https://github.com/obscuren" - }, - { - "name": "Marek Kotewicz", - "email": "marek@ethdev.com", - "url": "https://github.com/debris" - }, - { - "name": "Marian Oancea", - "email": "marian@ethdev.com", - "url": "https://github.com/cubedro" - } - ], - "license": "LGPL-3.0" -} diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index 06a7bc2a8e..5df4c8aad2 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -866,12 +866,14 @@ ApplicationWindow { model: ListModel { id: pastPeers } Component.onCompleted: { + /* var ips = eth.pastPeers() for(var i = 0; i < ips.length; i++) { pastPeers.append({text: ips.get(i)}) } pastPeers.insert(0, {text: "poc-7.ethdev.com:30303"}) + */ } } diff --git a/cmd/mist/assets/qml/views/wallet.qml b/cmd/mist/assets/qml/views/wallet.qml index 9727ef35c8..b81273a173 100644 --- a/cmd/mist/assets/qml/views/wallet.qml +++ b/cmd/mist/assets/qml/views/wallet.qml @@ -20,7 +20,7 @@ Rectangle { } function setBalance() { - balance.text = "Balance: " + eth.numberToHuman(eth.balanceAt(eth.key().address)) + //balance.text = "Balance: " + eth.numberToHuman(eth.balanceAt(eth.key().address)) if(menuItem) menuItem.secondaryTitle = eth.numberToHuman(eth.balanceAt(eth.key().address)) } diff --git a/cmd/mist/bindings.go b/cmd/mist/bindings.go index 6d2342c876..66d8d14916 100644 --- a/cmd/mist/bindings.go +++ b/cmd/mist/bindings.go @@ -72,7 +72,7 @@ func (gui *Gui) GetCustomIdentifier() string { // functions that allow Gui to implement interface guilogger.LogSystem func (gui *Gui) SetLogLevel(level logger.LogLevel) { gui.logLevel = level - gui.stdLog.SetLogLevel(level) + gui.eth.Logger().SetLogLevel(level) gui.config.Save("loglevel", level) } diff --git a/cmd/mist/debugger.go b/cmd/mist/debugger.go index 0e97a6652c..618e31f4ed 100644 --- a/cmd/mist/debugger.go +++ b/cmd/mist/debugger.go @@ -151,7 +151,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data block := self.lib.eth.ChainManager().CurrentBlock() - env := utils.NewEnv(statedb, block, account.Address(), value) + env := utils.NewEnv(self.lib.eth.ChainManager(), statedb, block, account.Address(), value) self.Logf("callsize %d", len(script)) go func() { diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index 98ca70b162..8e533d9772 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -72,8 +72,7 @@ type Gui struct { plugins map[string]plugin - miner *miner.Miner - stdLog logger.LogSystem + miner *miner.Miner } // Create GUI, but doesn't start it @@ -113,7 +112,7 @@ func (gui *Gui) Start(assetPath string) { // Expose the eth library and the ui library to QML context.SetVar("gui", gui) context.SetVar("eth", gui.uiLib) - context.SetVar("shh", gui.whisper) + //context.SetVar("shh", gui.whisper) // Load the main QML interface data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) diff --git a/cmd/mist/main.go b/cmd/mist/main.go index 6f578ff48f..ce5e8449a0 100644 --- a/cmd/mist/main.go +++ b/cmd/mist/main.go @@ -26,15 +26,17 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/p2p" "gopkg.in/qml.v1" ) const ( ClientIdentifier = "Mist" - Version = "0.7.11" + Version = "0.8.0" ) var ethereum *eth.Ethereum +var mainlogger = logger.NewLogger("MAIN") func run() error { // precedence: code-internal flag default < config file < environment variables < command line @@ -43,27 +45,24 @@ func run() error { tstart := time.Now() config := utils.InitConfig(VmType, ConfigFile, Datadir, "ETH") - utils.InitDataDir(Datadir) - - stdLog := utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile) - - db := utils.NewDatabase() - err := utils.DBSanityCheck(db) + ethereum, err := eth.New(ð.Config{ + Name: ClientIdentifier, + Version: Version, + KeyStore: KeyStore, + DataDir: Datadir, + LogFile: LogFile, + LogLevel: LogLevel, + Identifier: Identifier, + MaxPeers: MaxPeer, + Port: OutboundPort, + NATType: PMPGateway, + PMPGateway: PMPGateway, + KeyRing: KeyRing, + }) if err != nil { - ErrorWindow(err) - - os.Exit(1) - } - keyManager := utils.NewKeyManager(KeyStore, Datadir, db) - - // create, import, export keys - utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) - clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier, string(keyManager.PublicKey())) - ethereum := utils.NewEthereum(db, clientIdentity, keyManager, utils.NatType(NatType, PMPGateway), OutboundPort, MaxPeer) - - if ShowGenesis { - utils.ShowGenesis(ethereum) + mainlogger.Fatalln(err) } + utils.KeyTasks(ethereum.KeyManager(), KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) if StartRpc { utils.StartRpc(ethereum, RpcPort) @@ -73,8 +72,7 @@ func run() error { utils.StartWebSockets(ethereum) } - gui := NewWindow(ethereum, config, clientIdentity, KeyRing, LogLevel) - gui.stdLog = stdLog + gui := NewWindow(ethereum, config, ethereum.ClientIdentity().(*p2p.SimpleClientIdentity), KeyRing, LogLevel) utils.RegisterInterrupt(func(os.Signal) { gui.Stop() diff --git a/cmd/peerserver/main.go b/cmd/peerserver/main.go index 0fa7a9b440..18d183f0bd 100644 --- a/cmd/peerserver/main.go +++ b/cmd/peerserver/main.go @@ -18,7 +18,7 @@ func main() { marshaled := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y) srv := p2p.Server{ - MaxPeers: 10, + MaxPeers: 100, Identity: p2p.NewSimpleClientIdentity("Ethereum(G)", "0.1", "Peer Server Two", string(marshaled)), ListenAddr: ":30301", NAT: p2p.UPNP(), @@ -29,12 +29,12 @@ func main() { } // add seed peers - seed, err := net.ResolveTCPAddr("tcp", "poc-7.ethdev.com:30300") + seed, err := net.ResolveTCPAddr("tcp", "poc-8.ethdev.com:30303") if err != nil { fmt.Println("couldn't resolve:", err) - os.Exit(1) + } else { + srv.SuggestPeer(seed.IP, seed.Port, nil) } - srv.SuggestPeer(seed.IP, seed.Port, nil) select {} } diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 466c513835..6b1cf37265 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -2,9 +2,6 @@ package utils import ( "fmt" - "io" - "log" - "net" "os" "os/signal" "path" @@ -16,11 +13,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/xeth" @@ -52,15 +47,8 @@ func RunInterruptCallbacks(sig os.Signal) { } } -func AbsolutePath(Datadir string, filename string) string { - if path.IsAbs(filename) { - return filename - } - return path.Join(Datadir, filename) -} - func openLogFile(Datadir string, filename string) *os.File { - path := AbsolutePath(Datadir, filename) + path := ethutil.AbsolutePath(Datadir, filename) file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { panic(fmt.Sprintf("error opening log file '%s': %v", filename, err)) @@ -76,23 +64,13 @@ func confirm(message string) bool { if r == "n" || r == "y" { break } else { - fmt.Printf("Yes or no?", r) + fmt.Printf("Yes or no? (%s)", r) } } return r == "y" } -func DBSanityCheck(db ethutil.Database) error { - d, _ := db.Get([]byte("ProtocolVersion")) - protov := ethutil.NewValue(d).Uint() - if protov != eth.ProtocolVersion && protov != 0 { - return fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, eth.ProtocolVersion, ethutil.Config.ExecPath+"/database") - } - - return nil -} - -func InitDataDir(Datadir string) { +func initDataDir(Datadir string) { _, err := os.Stat(Datadir) if err != nil { if os.IsNotExist(err) { @@ -102,26 +80,8 @@ func InitDataDir(Datadir string) { } } -func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) logger.LogSystem { - var writer io.Writer - if LogFile == "" { - writer = os.Stdout - } else { - writer = openLogFile(Datadir, LogFile) - } - - sys := logger.NewStdLogSystem(writer, log.LstdFlags, logger.LogLevel(LogLevel)) - logger.AddLogSystem(sys) - if DebugFile != "" { - writer = openLogFile(Datadir, DebugFile) - logger.AddLogSystem(logger.NewStdLogSystem(writer, log.LstdFlags, logger.DebugLevel)) - } - - return sys -} - func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager { - InitDataDir(Datadir) + initDataDir(Datadir) cfg := ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix) cfg.VmType = vmType @@ -138,43 +98,6 @@ func exit(err error) { os.Exit(status) } -func NewDatabase() ethutil.Database { - db, err := ethdb.NewLDBDatabase("database") - if err != nil { - exit(err) - } - return db -} - -func NewClientIdentity(clientIdentifier, version, customIdentifier string, pubkey string) *p2p.SimpleClientIdentity { - return p2p.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier, pubkey) -} - -func NatType(natType string, gateway string) (nat p2p.NAT) { - switch natType { - case "UPNP": - nat = p2p.UPNP() - case "PMP": - ip := net.ParseIP(gateway) - if ip == nil { - clilogger.Fatalf("cannot resolve PMP gateway IP %s", gateway) - } - nat = p2p.PMP(ip) - case "": - default: - clilogger.Fatalf("unrecognised NAT type '%s'", natType) - } - return -} - -func NewEthereum(db ethutil.Database, clientIdentity p2p.ClientIdentity, keyManager *crypto.KeyManager, nat p2p.NAT, OutboundPort string, MaxPeer int) *eth.Ethereum { - ethereum, err := eth.New(db, clientIdentity, keyManager, nat, OutboundPort, MaxPeer) - if err != nil { - clilogger.Fatalln("eth start err:", err) - } - return ethereum -} - func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) { clilogger.Infof("Starting %s", ethereum.ClientIdentity()) ethereum.Start(UseSeed) @@ -184,24 +107,6 @@ func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) { }) } -func ShowGenesis(ethereum *eth.Ethereum) { - clilogger.Infoln(ethereum.ChainManager().Genesis()) - exit(nil) -} - -func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *crypto.KeyManager { - var keyManager *crypto.KeyManager - switch { - case KeyStore == "db": - keyManager = crypto.NewDBKeyManager(db) - case KeyStore == "file": - keyManager = crypto.NewFileKeyManager(Datadir) - default: - exit(fmt.Errorf("unknown keystore type: %s", KeyStore)) - } - return keyManager -} - func DefaultAssetPath() string { var assetPath string // If the current working directory is the go-ethereum dir diff --git a/cmd/utils/vm_env.go b/cmd/utils/vm_env.go index 19091bdc5d..acc2ffad95 100644 --- a/cmd/utils/vm_env.go +++ b/cmd/utils/vm_env.go @@ -10,6 +10,7 @@ import ( ) type VMEnv struct { + chain *core.ChainManager state *state.StateDB block *types.Block @@ -20,8 +21,9 @@ type VMEnv struct { Gas *big.Int } -func NewEnv(state *state.StateDB, block *types.Block, transactor []byte, value *big.Int) *VMEnv { +func NewEnv(chain *core.ChainManager, state *state.StateDB, block *types.Block, transactor []byte, value *big.Int) *VMEnv { return &VMEnv{ + chain: chain, state: state, block: block, transactor: transactor, @@ -35,12 +37,18 @@ func (self *VMEnv) PrevHash() []byte { return self.block.ParentHash() } func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } func (self *VMEnv) Time() int64 { return self.block.Time() } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } -func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) Depth() int { return self.depth } func (self *VMEnv) SetDepth(i int) { self.depth = i } +func (self *VMEnv) GetHash(n uint64) []byte { + if block := self.chain.GetBlockByNumber(n); block != nil { + return block.Hash() + } + + return nil +} func (self *VMEnv) AddLog(log state.Log) { self.state.AddLog(log) } diff --git a/core/block_manager.go b/core/block_manager.go index 8a5455306c..76385ea1fd 100644 --- a/core/block_manager.go +++ b/core/block_manager.go @@ -6,7 +6,6 @@ import ( "fmt" "math/big" "sync" - "time" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -22,18 +21,6 @@ import ( var statelogger = logger.NewLogger("BLOCK") -type Peer interface { - Inbound() bool - LastSend() time.Time - LastPong() int64 - Host() []byte - Port() uint16 - Version() string - PingTime() string - Connected() *int32 - Caps() *ethutil.Value -} - type EthManager interface { BlockManager() *BlockManager ChainManager() *ChainManager @@ -113,7 +100,7 @@ done: txGas := new(big.Int).Set(tx.Gas()) cb := state.GetStateObject(coinbase.Address()) - st := NewStateTransition(cb, tx, state, block) + st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb) _, err = st.TransitionState() if err != nil { switch { @@ -232,6 +219,8 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I // Sync the current block's state to the database and cancelling out the deferred Undo state.Sync() + state.Manifest().SetHash(block.Hash()) + messages := state.Manifest().Messages state.Manifest().Reset() @@ -339,10 +328,10 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent account.AddAmount(reward) statedb.Manifest().AddMessage(&state.Message{ - To: block.Header().Coinbase, - Input: nil, - Origin: nil, - Block: block.Hash(), Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number, + To: block.Header().Coinbase, + Input: nil, + Origin: nil, + Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number, Value: new(big.Int).Add(reward, block.Reward), }) diff --git a/core/chain_manager.go b/core/chain_manager.go index ece98d7830..82b17cd931 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -271,15 +271,15 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { self.mu.RLock() defer self.mu.RUnlock() - block := self.currentBlock - for ; block != nil; block = self.GetBlock(block.Header().ParentHash) { - if block.Header().Number.Uint64() == num { - break - } - } + var block *types.Block - if block != nil && block.Header().Number.Uint64() == 0 && num != 0 { - return nil + if num <= self.currentBlock.Number().Uint64() { + block = self.currentBlock + for ; block != nil; block = self.GetBlock(block.Header().ParentHash) { + if block.Header().Number.Uint64() == num { + break + } + } } return block diff --git a/core/state_transition.go b/core/state_transition.go index 91cfd5fe3b..b22c5bf217 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -4,7 +4,6 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/state" @@ -28,18 +27,17 @@ import ( * 6) Derive new state root */ type StateTransition struct { - coinbase, receiver []byte - msg Message - gas, gasPrice *big.Int - initialGas *big.Int - value *big.Int - data []byte - state *state.StateDB - block *types.Block + coinbase []byte + msg Message + gas, gasPrice *big.Int + initialGas *big.Int + value *big.Int + data []byte + state *state.StateDB cb, rec, sen *state.StateObject - Env vm.Environment + env vm.Environment } type Message interface { @@ -69,16 +67,19 @@ func MessageGasValue(msg Message) *big.Int { return new(big.Int).Mul(msg.Gas(), msg.GasPrice()) } -func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *StateTransition { - return &StateTransition{coinbase.Address(), msg.To(), msg, new(big.Int), new(big.Int).Set(msg.GasPrice()), new(big.Int), msg.Value(), msg.Data(), state, block, coinbase, nil, nil, nil} -} - -func (self *StateTransition) VmEnv() vm.Environment { - if self.Env == nil { - self.Env = NewEnv(self.state, self.msg, self.block) +func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateObject) *StateTransition { + return &StateTransition{ + coinbase: coinbase.Address(), + env: env, + msg: msg, + gas: new(big.Int), + gasPrice: new(big.Int).Set(msg.GasPrice()), + initialGas: new(big.Int), + value: msg.Value(), + data: msg.Data(), + state: env.State(), + cb: coinbase, } - - return self.Env } func (self *StateTransition) Coinbase() *state.StateObject { @@ -183,7 +184,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { return } - vmenv := self.VmEnv() + vmenv := self.env var ref vm.ContextRef if MessageCreatesContract(msg) { contract := MakeContract(msg, self.state) diff --git a/core/vm_env.go b/core/vm_env.go index 4e0315ff3b..624a633334 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -13,10 +13,12 @@ type VMEnv struct { block *types.Block msg Message depth int + chain *ChainManager } -func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv { +func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv { return &VMEnv{ + chain: chain, state: state, block: block, msg: msg, @@ -25,16 +27,21 @@ func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv { func (self *VMEnv) Origin() []byte { return self.msg.From() } func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } -func (self *VMEnv) PrevHash() []byte { return self.block.ParentHash() } func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } func (self *VMEnv) Time() int64 { return self.block.Time() } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } -func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } func (self *VMEnv) Value() *big.Int { return self.msg.Value() } func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) Depth() int { return self.depth } func (self *VMEnv) SetDepth(i int) { self.depth = i } +func (self *VMEnv) GetHash(n uint64) []byte { + if block := self.chain.GetBlockByNumber(n); block != nil { + return block.Hash() + } + + return nil +} func (self *VMEnv) AddLog(log state.Log) { self.state.AddLog(log) } diff --git a/eth/backend.go b/eth/backend.go index 36c1ac30f3..bf6c912826 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -1,11 +1,13 @@ package eth import ( + "fmt" "net" "sync" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/event" ethlogger "github.com/ethereum/go-ethereum/logger" @@ -19,6 +21,24 @@ const ( seedNodeAddress = "poc-7.ethdev.com:30300" ) +type Config struct { + Name string + Version string + Identifier string + KeyStore string + DataDir string + LogFile string + LogLevel int + KeyRing string + + MaxPeers int + Port string + NATType string + PMPGateway string + + KeyManager *crypto.KeyManager +} + var logger = ethlogger.NewLogger("SERV") type Ethereum struct { @@ -38,7 +58,7 @@ type Ethereum struct { blockPool *BlockPool whisper *whisper.Whisper - server *p2p.Server + net *p2p.Server eventMux *event.TypeMux txSub event.Subscription blockSub event.Subscription @@ -47,6 +67,7 @@ type Ethereum struct { keyManager *crypto.KeyManager clientIdentity p2p.ClientIdentity + logger ethlogger.LogSystem synclock sync.Mutex syncGroup sync.WaitGroup @@ -54,7 +75,36 @@ type Ethereum struct { Mining bool } -func New(db ethutil.Database, identity p2p.ClientIdentity, keyManager *crypto.KeyManager, nat p2p.NAT, port string, maxPeers int) (*Ethereum, error) { +func New(config *Config) (*Ethereum, error) { + // Boostrap database + logger := ethlogger.New(config.DataDir, config.LogFile, config.LogLevel) + db, err := ethdb.NewLDBDatabase("database") + if err != nil { + return nil, err + } + + // Perform database sanity checks + d, _ := db.Get([]byte("ProtocolVersion")) + protov := ethutil.NewValue(d).Uint() + if protov != ProtocolVersion && protov != 0 { + return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, ethutil.Config.ExecPath+"/database") + } + + // Create new keymanager + var keyManager *crypto.KeyManager + switch config.KeyStore { + case "db": + keyManager = crypto.NewDBKeyManager(db) + case "file": + keyManager = crypto.NewFileKeyManager(config.DataDir) + default: + return nil, fmt.Errorf("unknown keystore type: %s", config.KeyStore) + } + // Initialise the keyring + keyManager.Init(config.KeyRing, 0, false) + + // Create a new client id for this instance. This will help identifying the node on the network + clientId := p2p.NewSimpleClientIdentity(config.Name, config.Version, config.Identifier, keyManager.PublicKey()) saveProtocolVersion(db) ethutil.Config.Db = db @@ -64,9 +114,10 @@ func New(db ethutil.Database, identity p2p.ClientIdentity, keyManager *crypto.Ke quit: make(chan bool), db: db, keyManager: keyManager, - clientIdentity: identity, + clientIdentity: clientId, blacklist: p2p.NewBlacklist(), eventMux: &event.TypeMux{}, + logger: logger, } eth.chainManager = core.NewChainManager(eth.EventMux()) @@ -85,17 +136,20 @@ func New(db ethutil.Database, identity p2p.ClientIdentity, keyManager *crypto.Ke ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool) protocols := []p2p.Protocol{ethProto, eth.whisper.Protocol()} - server := &p2p.Server{ - Identity: identity, - MaxPeers: maxPeers, + nat, err := p2p.ParseNAT(config.NATType, config.PMPGateway) + if err != nil { + return nil, err + } + + eth.net = &p2p.Server{ + Identity: clientId, + MaxPeers: config.MaxPeers, Protocols: protocols, - ListenAddr: ":" + port, + ListenAddr: ":" + config.Port, Blacklist: eth.blacklist, NAT: nat, } - eth.server = server - return eth, nil } @@ -103,6 +157,10 @@ func (s *Ethereum) KeyManager() *crypto.KeyManager { return s.keyManager } +func (s *Ethereum) Logger() ethlogger.LogSystem { + return s.logger +} + func (s *Ethereum) ClientIdentity() p2p.ClientIdentity { return s.clientIdentity } @@ -144,20 +202,20 @@ func (s *Ethereum) IsListening() bool { } func (s *Ethereum) PeerCount() int { - return s.server.PeerCount() + return s.net.PeerCount() } func (s *Ethereum) Peers() []*p2p.Peer { - return s.server.Peers() + return s.net.Peers() } func (s *Ethereum) MaxPeers() int { - return s.server.MaxPeers + return s.net.MaxPeers } // Start the ethereum func (s *Ethereum) Start(seed bool) error { - err := s.server.Start() + err := s.net.Start() if err != nil { return err } @@ -191,7 +249,7 @@ func (self *Ethereum) SuggestPeer(addr string) error { return err } - self.server.SuggestPeer(netaddr.IP, netaddr.Port, nil) + self.net.SuggestPeer(netaddr.IP, netaddr.Port, nil) return nil } @@ -227,7 +285,7 @@ func (self *Ethereum) txBroadcastLoop() { // automatically stops if unsubscribe for obj := range self.txSub.Chan() { event := obj.(core.TxPreEvent) - self.server.Broadcast("eth", TxMsg, []interface{}{event.Tx.RlpData()}) + self.net.Broadcast("eth", TxMsg, []interface{}{event.Tx.RlpData()}) } } @@ -236,7 +294,7 @@ func (self *Ethereum) blockBroadcastLoop() { for obj := range self.txSub.Chan() { switch ev := obj.(type) { case core.NewMinedBlockEvent: - self.server.Broadcast("eth", NewBlockMsg, ev.Block.RlpData()) + self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData()) } } } diff --git a/ethutil/path.go b/ethutil/path.go index cfbc389508..f64e3849e0 100644 --- a/ethutil/path.go +++ b/ethutil/path.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" "os/user" + "path" "strings" ) @@ -58,3 +59,10 @@ func WriteFile(filePath string, content []byte) error { return nil } + +func AbsolutePath(Datadir string, filename string) string { + if path.IsAbs(filename) { + return filename + } + return path.Join(Datadir, filename) +} diff --git a/logger/log.go b/logger/log.go new file mode 100644 index 0000000000..53065f870b --- /dev/null +++ b/logger/log.go @@ -0,0 +1,33 @@ +package logger + +import ( + "fmt" + "io" + "log" + "os" + + "github.com/ethereum/go-ethereum/ethutil" +) + +func openLogFile(datadir string, filename string) *os.File { + path := ethutil.AbsolutePath(datadir, filename) + file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + panic(fmt.Sprintf("error opening log file '%s': %v", filename, err)) + } + return file +} + +func New(datadir string, logFile string, logLevel int) LogSystem { + var writer io.Writer + if logFile == "" { + writer = os.Stdout + } else { + writer = openLogFile(datadir, logFile) + } + + sys := NewStdLogSystem(writer, log.LstdFlags, LogLevel(logLevel)) + AddLogSystem(sys) + + return sys +} diff --git a/p2p/client_identity.go b/p2p/client_identity.go index bc865b63b0..f15fd01bfc 100644 --- a/p2p/client_identity.go +++ b/p2p/client_identity.go @@ -17,10 +17,10 @@ type SimpleClientIdentity struct { customIdentifier string os string implementation string - pubkey string + pubkey []byte } -func NewSimpleClientIdentity(clientIdentifier string, version string, customIdentifier string, pubkey string) *SimpleClientIdentity { +func NewSimpleClientIdentity(clientIdentifier string, version string, customIdentifier string, pubkey []byte) *SimpleClientIdentity { clientIdentity := &SimpleClientIdentity{ clientIdentifier: clientIdentifier, version: version, diff --git a/p2p/nat.go b/p2p/nat.go new file mode 100644 index 0000000000..9b771c3e8c --- /dev/null +++ b/p2p/nat.go @@ -0,0 +1,23 @@ +package p2p + +import ( + "fmt" + "net" +) + +func ParseNAT(natType string, gateway string) (nat NAT, err error) { + switch natType { + case "UPNP": + nat = UPNP() + case "PMP": + ip := net.ParseIP(gateway) + if ip == nil { + return nil, fmt.Errorf("cannot resolve PMP gateway IP %s", gateway) + } + nat = PMP(ip) + case "": + default: + return nil, fmt.Errorf("unrecognised NAT type '%s'", natType) + } + return +} diff --git a/core/dagger.go b/pow/dagger/dagger.go similarity index 99% rename from core/dagger.go rename to pow/dagger/dagger.go index 3039d89959..9ac0004433 100644 --- a/core/dagger.go +++ b/pow/dagger/dagger.go @@ -1,4 +1,4 @@ -package core +package dagger import ( "hash" diff --git a/core/dagger_test.go b/pow/dagger/dagger_test.go similarity index 96% rename from core/dagger_test.go rename to pow/dagger/dagger_test.go index e80064e6bf..f3a71d1eb4 100644 --- a/core/dagger_test.go +++ b/pow/dagger/dagger_test.go @@ -1,4 +1,4 @@ -package core +package dagger import ( "math/big" diff --git a/state/manifest.go b/state/manifest.go index 21cd04a1a9..994019a086 100644 --- a/state/manifest.go +++ b/state/manifest.go @@ -30,6 +30,12 @@ func (self *Manifest) AddMessage(msg *Message) *Message { return msg } +func (self *Manifest) SetHash(hash []byte) { + for _, message := range self.Messages { + message.Block = hash + } +} + type Messages []*Message type Message struct { To, From []byte diff --git a/tests/helper/vm.go b/tests/helper/vm.go index aa17313b77..123003faa3 100644 --- a/tests/helper/vm.go +++ b/tests/helper/vm.go @@ -55,9 +55,11 @@ func (self *Env) PrevHash() []byte { return self.parent } func (self *Env) Coinbase() []byte { return self.coinbase } func (self *Env) Time() int64 { return self.time } func (self *Env) Difficulty() *big.Int { return self.difficulty } -func (self *Env) BlockHash() []byte { return nil } func (self *Env) State() *state.StateDB { return self.state } func (self *Env) GasLimit() *big.Int { return self.gasLimit } +func (self *Env) GetHash(n uint64) []byte { + return nil +} func (self *Env) AddLog(log state.Log) { self.logs = append(self.logs, log) } @@ -126,10 +128,9 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state. message := NewMessage(keyPair.Address(), to, data, value, gas, price) Log.DebugDetailf("message{ to: %x, from %x, value: %v, gas: %v, price: %v }\n", message.to[:4], message.from[:4], message.value, message.gas, message.price) - st := core.NewStateTransition(coinbase, message, statedb, nil) vmenv := NewEnvFromMap(statedb, env, tx) + st := core.NewStateTransition(vmenv, message, coinbase) vmenv.origin = keyPair.Address() - st.Env = vmenv ret, err := st.TransitionState() statedb.Update(vmenv.Gas) diff --git a/vm/context.go b/vm/context.go index ccbadabdaa..d14df1aa77 100644 --- a/vm/context.go +++ b/vm/context.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" ) type ContextRef interface { @@ -15,10 +14,9 @@ type ContextRef interface { } type Context struct { - caller ContextRef - object ContextRef - Code []byte - message *state.Message + caller ContextRef + object ContextRef + Code []byte Gas, UsedGas, Price *big.Int @@ -26,8 +24,8 @@ type Context struct { } // Create a new context for the given data items -func NewContext(msg *state.Message, caller ContextRef, object ContextRef, code []byte, gas, price *big.Int) *Context { - c := &Context{message: msg, caller: caller, object: object, Code: code, Args: nil} +func NewContext(caller ContextRef, object ContextRef, code []byte, gas, price *big.Int) *Context { + c := &Context{caller: caller, object: object, Code: code, Args: nil} // Gas should be a pointer so it can safely be reduced through the run // This pointer will be off the state transition @@ -40,13 +38,13 @@ func NewContext(msg *state.Message, caller ContextRef, object ContextRef, code [ return c } -func (c *Context) GetOp(x uint64) OpCode { - return OpCode(c.GetByte(x)) +func (c *Context) GetOp(n uint64) OpCode { + return OpCode(c.GetByte(n)) } -func (c *Context) GetByte(x uint64) byte { - if x < uint64(len(c.Code)) { - return c.Code[x] +func (c *Context) GetByte(n uint64) byte { + if n < uint64(len(c.Code)) { + return c.Code[n] } return 0 diff --git a/vm/environment.go b/vm/environment.go index 01bbd56cea..8ec13ee412 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -14,11 +14,10 @@ type Environment interface { Origin() []byte BlockNumber() *big.Int - PrevHash() []byte + GetHash(n uint64) []byte Coinbase() []byte Time() int64 Difficulty() *big.Int - BlockHash() []byte GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error AddLog(state.Log) @@ -31,11 +30,6 @@ type Environment interface { Create(me ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) } -type Object interface { - GetStorage(key *big.Int) *ethutil.Value - SetStorage(key *big.Int, value *ethutil.Value) -} - type Account interface { SubBalance(amount *big.Int) AddBalance(amount *big.Int) diff --git a/vm/types.go b/vm/types.go index ec9c7e74e6..1ea80a212d 100644 --- a/vm/types.go +++ b/vm/types.go @@ -59,7 +59,7 @@ const ( const ( // 0x40 range - block operations - PREVHASH OpCode = 0x40 + iota + BLOCKHASH OpCode = 0x40 + iota COINBASE TIMESTAMP NUMBER @@ -216,7 +216,7 @@ var opCodeToString = map[OpCode]string{ GASPRICE: "TXGASPRICE", // 0x40 range - block operations - PREVHASH: "PREVHASH", + BLOCKHASH: "BLOCKHASH", COINBASE: "COINBASE", TIMESTAMP: "TIMESTAMP", NUMBER: "NUMBER", diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 6ad385fd0c..92e4154e4f 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -42,12 +42,12 @@ func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price * msg := self.env.State().Manifest().AddMessage(&state.Message{ To: me.Address(), From: caller.Address(), - Input: callData, - Origin: self.env.Origin(), - Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + Input: callData, + Origin: self.env.Origin(), + Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), Value: value, }) - context := NewContext(msg, caller, me, code, gas, price) + context := NewContext(caller, me, code, gas, price) if self.Recoverable { // Recover from any require exception @@ -83,7 +83,7 @@ func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price * jump = func(from uint64, to *big.Int) { p := to.Uint64() - nop := OpCode(context.GetOp(p)) + nop := context.GetOp(p) if !destinations.Has(p) { panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p)) } @@ -516,12 +516,15 @@ func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price * self.Printf(" => %v", context.Price) // 0x40 range - case PREVHASH: - prevHash := self.env.PrevHash() + case BLOCKHASH: + num := stack.Pop() + if num.Cmp(new(big.Int).Sub(self.env.BlockNumber(), ethutil.Big256)) < 0 { + stack.Push(ethutil.Big0) + } else { + stack.Push(ethutil.BigD(self.env.GetHash(num.Uint64()))) + } - stack.Push(ethutil.BigD(prevHash)) - - self.Printf(" => 0x%x", prevHash) + self.Printf(" => 0x%x", stack.Peek().Bytes()) case COINBASE: coinbase := self.env.Coinbase() @@ -614,7 +617,7 @@ func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price * val, loc := stack.Popn() statedb.SetState(context.Address(), loc.Bytes(), val) - context.message.AddStorageChange(loc.Bytes()) + msg.AddStorageChange(loc.Bytes()) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: diff --git a/xeth/pipe.go b/xeth/pipe.go index cae6ee1dec..05cefd8ad2 100644 --- a/xeth/pipe.go +++ b/xeth/pipe.go @@ -87,7 +87,7 @@ func (self *XEth) ExecuteObject(object *Object, data []byte, value, gas, price * self.Vm.State = self.World().State().Copy() - vmenv := NewEnv(self.Vm.State, block, value.BigInt(), initiator.Address()) + vmenv := NewEnv(self.chainManager, self.Vm.State, block, value.BigInt(), initiator.Address()) return vmenv.Call(initiator, object.Address(), data, gas.BigInt(), price.BigInt(), value.BigInt()) } diff --git a/xeth/vm_env.go b/xeth/vm_env.go index d2a21afd5d..1470b9eaa5 100644 --- a/xeth/vm_env.go +++ b/xeth/vm_env.go @@ -10,6 +10,7 @@ import ( ) type VMEnv struct { + chain *core.ChainManager state *state.StateDB block *types.Block value *big.Int @@ -18,7 +19,7 @@ type VMEnv struct { depth int } -func NewEnv(state *state.StateDB, block *types.Block, value *big.Int, sender []byte) *VMEnv { +func NewEnv(chain *core.ChainManager, state *state.StateDB, block *types.Block, value *big.Int, sender []byte) *VMEnv { return &VMEnv{ state: state, block: block, @@ -33,12 +34,18 @@ func (self *VMEnv) PrevHash() []byte { return self.block.ParentHash() } func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } func (self *VMEnv) Time() int64 { return self.block.Time() } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } -func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) Depth() int { return self.depth } func (self *VMEnv) SetDepth(i int) { self.depth = i } +func (self *VMEnv) GetHash(n uint64) []byte { + if block := self.chain.GetBlockByNumber(n); block != nil { + return block.Hash() + } + + return nil +} func (self *VMEnv) AddLog(log state.Log) { self.state.AddLog(log) }