Merging bug/whisper-on-geth1.6.1 (#236) which acts like develop

* static: updates Whisper test (to work with Geth 1.6.1)
* jail: VM persistence implemented
* jail: sendMessage/showSuggestions minor fixes (to be squashed)
* node: CHT and boot nodes auto-load implemented
* Replaced CHT data file from farazdagi's to tiabc's
* Rewrote config_test.go using testify having reduced it twice in size
* Increased SyncTime and panic timeout in tests
* Fixed test - remove go default test to testify/suite (#207)
* Add flag setup for RPCEnabled and add comment (#225)
* jail: register method handlers before running initial js in jail (#226)
* Console Jail Mod #179 (#228)
* Added ./statusd-data into .gitignore
* Increased log level for the test node from INFO to ERROR
* Add call to loop.Run to evaluate all setTimeout/setIntervals methods. (#208)
* Rebase onto geth1.6.7 (#232)
* Got back sync duration from 60s to 30s, updated bindata.go
This commit is contained in:
Ivan Tomilov 2017-08-04 23:14:17 +07:00 committed by GitHub
parent c274cf5222
commit ebd77aabe2
356 changed files with 18883 additions and 6491 deletions

2
.gitignore vendored
View File

@ -4,6 +4,8 @@
# or operating system, you probably want to add a global ignore instead: # or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore_global # git config --global core.excludesfile ~/.gitignore_global
/statusd-data
/tmp /tmp
*/**/*un~ */**/*un~
*/**/*.test */**/*.test

View File

@ -56,6 +56,7 @@ func parseFaucetCommandConfig(ctx *cli.Context) (*params.NodeConfig, error) {
nodeConfig.APIModules = "eth" nodeConfig.APIModules = "eth"
nodeConfig.HTTPHost = "0.0.0.0" // allow to connect from anywhere nodeConfig.HTTPHost = "0.0.0.0" // allow to connect from anywhere
nodeConfig.HTTPPort = ctx.Int(HTTPPortFlag.Name) nodeConfig.HTTPPort = ctx.Int(HTTPPortFlag.Name)
nodeConfig.RPCEnabled = ctx.Bool(HTTPEnabledFlag.Name)
// extra options // extra options
nodeConfig.BootClusterConfig.Enabled = true nodeConfig.BootClusterConfig.Enabled = true

View File

@ -53,6 +53,7 @@ func parseLESCommandConfig(ctx *cli.Context) (*params.NodeConfig, error) {
// Enabled sub-protocols // Enabled sub-protocols
nodeConfig.LightEthConfig.Enabled = true nodeConfig.LightEthConfig.Enabled = true
nodeConfig.RPCEnabled = ctx.Bool(HTTPEnabledFlag.Name)
nodeConfig.WhisperConfig.Enabled = ctx.Bool(WhisperEnabledFlag.Name) nodeConfig.WhisperConfig.Enabled = ctx.Bool(WhisperEnabledFlag.Name)
nodeConfig.SwarmConfig.Enabled = ctx.Bool(SwarmEnabledFlag.Name) nodeConfig.SwarmConfig.Enabled = ctx.Bool(SwarmEnabledFlag.Name)

View File

@ -66,7 +66,7 @@ var (
// HTTPEnabledFlag defines whether HTTP RPC endpoint should be opened or not // HTTPEnabledFlag defines whether HTTP RPC endpoint should be opened or not
HTTPEnabledFlag = cli.BoolFlag{ HTTPEnabledFlag = cli.BoolFlag{
Name: "http", Name: "http",
Usage: "HTTP RPC enpoint enabled", Usage: "HTTP RPC enpoint enabled (default: false)",
} }
// HTTPPortFlag defines HTTP RPC port to use (if HTTP RPC is enabled) // HTTPPortFlag defines HTTP RPC port to use (if HTTP RPC is enabled)

View File

@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/les/status" "github.com/ethereum/go-ethereum/les/status"
gethparams "github.com/ethereum/go-ethereum/params" gethparams "github.com/ethereum/go-ethereum/params"
"github.com/status-im/status-go/geth/common" "github.com/status-im/status-go/geth/common"
"github.com/status-im/status-go/geth/node" "github.com/status-im/status-go/geth/node"
"github.com/status-im/status-go/geth/params" "github.com/status-im/status-go/geth/params"
@ -95,6 +96,14 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
"test discard multiple queued transactions", "test discard multiple queued transactions",
testDiscardMultipleQueuedTransactions, testDiscardMultipleQueuedTransactions,
}, },
{
"test jail invalid initialization",
testJailInitInvalid,
},
{
"test jail invalid parse",
testJailParseInvalid,
},
{ {
"test jail initialization", "test jail initialization",
testJailInit, testJailInit,
@ -170,11 +179,11 @@ func testGetDefaultConfig(t *testing.T) bool {
return false return false
} }
chainConfig := genesis.Config chainConfig := genesis.Config
if chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock) != 0 { if chainConfig.HomesteadBlock.Cmp(gethparams.MainnetChainConfig.HomesteadBlock) != 0 {
t.Error("invalid chainConfig.HomesteadBlock") t.Error("invalid chainConfig.HomesteadBlock")
return false return false
} }
if chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock) != 0 { if chainConfig.DAOForkBlock.Cmp(gethparams.MainnetChainConfig.DAOForkBlock) != 0 {
t.Error("invalid chainConfig.DAOForkBlock") t.Error("invalid chainConfig.DAOForkBlock")
return false return false
} }
@ -182,23 +191,23 @@ func testGetDefaultConfig(t *testing.T) bool {
t.Error("invalid chainConfig.DAOForkSupport") t.Error("invalid chainConfig.DAOForkSupport")
return false return false
} }
if chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock) != 0 { if chainConfig.EIP150Block.Cmp(gethparams.MainnetChainConfig.EIP150Block) != 0 {
t.Error("invalid chainConfig.EIP150Block") t.Error("invalid chainConfig.EIP150Block")
return false return false
} }
if chainConfig.EIP150Hash != gethparams.MainNetHomesteadGasRepriceHash { if chainConfig.EIP150Hash != gethparams.MainnetChainConfig.EIP150Hash {
t.Error("invalid chainConfig.EIP150Hash") t.Error("invalid chainConfig.EIP150Hash")
return false return false
} }
if chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 { if chainConfig.EIP155Block.Cmp(gethparams.MainnetChainConfig.EIP155Block) != 0 {
t.Error("invalid chainConfig.EIP155Block") t.Error("invalid chainConfig.EIP155Block")
return false return false
} }
if chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 { if chainConfig.EIP158Block.Cmp(gethparams.MainnetChainConfig.EIP158Block) != 0 {
t.Error("invalid chainConfig.EIP158Block") t.Error("invalid chainConfig.EIP158Block")
return false return false
} }
if chainConfig.ChainId.Cmp(gethparams.MainNetChainID) != 0 { if chainConfig.ChainId.Cmp(gethparams.MainnetChainConfig.ChainId) != 0 {
t.Error("invalid chainConfig.ChainId") t.Error("invalid chainConfig.ChainId")
return false return false
} }
@ -986,7 +995,7 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool {
select { select {
case <-allTestTxCompleted: case <-allTestTxCompleted:
// pass // pass
case <-time.After(20 * time.Second): case <-time.After(20 * time.Second):
t.Error("test timed out") t.Error("test timed out")
return false return false
@ -1284,7 +1293,7 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
select { select {
case <-allTestTxDiscarded: case <-allTestTxDiscarded:
// pass // pass
case <-time.After(20 * time.Second): case <-time.After(20 * time.Second):
t.Error("test timed out") t.Error("test timed out")
return false return false
@ -1298,6 +1307,51 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
return true return true
} }
func testJailInitInvalid(t *testing.T) bool {
// Arrange.
initInvalidCode := `
var _status_catalog = {
foo: 'bar'
`
// Act.
InitJail(C.CString(initInvalidCode))
response := C.GoString(Parse(C.CString("CHAT_ID_INIT_TEST"), C.CString(``)))
// Assert.
expectedResponse := `{"error":"(anonymous): Line 4:3 Unexpected end of input (and 3 more errors)"}`
if expectedResponse != response {
t.Errorf("unexpected response, expected: %v, got: %v", expectedResponse, response)
return false
}
return true
}
func testJailParseInvalid(t *testing.T) bool {
// Arrange.
initCode := `
var _status_catalog = {
foo: 'bar'
};
`
// Act.
InitJail(C.CString(initCode))
extraInvalidCode := `
var extraFunc = function (x) {
return x * x;
`
response := C.GoString(Parse(C.CString("CHAT_ID_INIT_TEST"), C.CString(extraInvalidCode)))
// Assert.
expectedResponse := `{"error":"(anonymous): Line 16331:50 Unexpected end of input (and 1 more errors)"}`
if expectedResponse != response {
t.Errorf("unexpected response, expected: %v, got: %v", expectedResponse, response)
return false
}
return true
}
func testJailInit(t *testing.T) bool { func testJailInit(t *testing.T) bool {
initCode := ` initCode := `
var _status_catalog = { var _status_catalog = {

View File

@ -40,7 +40,7 @@ func (s *APITestSuite) TestCHTUpdate() {
require.NoError(err) require.NoError(err)
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
url := "https://gist.githubusercontent.com/farazdagi/3d05d1d3bfa36db7b650c955e23fd7ae/raw/?u=" + strconv.Itoa(int(time.Now().Unix())) url := "https://gist.githubusercontent.com/tiabc/83ed515fbb0c0e9d39700a6279072b6a/raw/a8c7b08488fab3c1d9139b18af33da3df823e3ff/cht.json?u=" + strconv.Itoa(int(time.Now().Unix()))
configJSON := `{ configJSON := `{
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `, "NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
"DataDir": "` + tmpDir + `", "DataDir": "` + tmpDir + `",
@ -51,14 +51,15 @@ func (s *APITestSuite) TestCHTUpdate() {
"CHTRootConfigURL": "` + url + `" "CHTRootConfigURL": "` + url + `"
} }
}` }`
nodeConfig, err := params.LoadNodeConfig(configJSON) //nodeConfig, err := params.LoadNodeConfig(configJSON)
_, err = params.LoadNodeConfig(configJSON)
require.NoError(err) require.NoError(err)
// start node // start node
nodeConfig.DevMode = true //nodeConfig.DevMode = true
s.api.StartNode(nodeConfig) //s.api.StartNode(nodeConfig)
time.Sleep(TestConfig.Node.SyncSeconds * time.Second) //s.api.StopNode()
s.api.StopNode() // TODO(tiabc): Test that CHT is really updated.
} }
func (s *APITestSuite) TestRaceConditions() { func (s *APITestSuite) TestRaceConditions() {

View File

@ -1,10 +1,12 @@
package api_test package api_test
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
gethcommon "github.com/ethereum/go-ethereum/common" gethcommon "github.com/ethereum/go-ethereum/common"
@ -30,103 +32,24 @@ const (
testChatID = "testChat" testChatID = "testChat"
) )
func (s *BackendTestSuite) TestJailContractDeployment() {
require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
time.Sleep(TestConfig.Node.SyncSeconds * time.Second) // allow to sync
jailInstance := s.backend.JailManager()
require.NotNil(jailInstance)
jailInstance.Parse(testChatID, "")
// obtain VM for a given chat (to send custom JS to jailed version of Send())
vm, err := jailInstance.JailCellVM(testChatID)
require.NoError(err)
// make sure you panic if transaction complete doesn't return
completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(30*time.Second, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler
var txHash gethcommon.Hash
node.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
var envelope node.SignalEnvelope
err := json.Unmarshal([]byte(jsonEvent), &envelope)
s.NoError(err, fmt.Sprintf("cannot unmarshal JSON: %s", jsonEvent))
if envelope.Type == node.EventTransactionQueued {
event := envelope.Event.(map[string]interface{})
log.Info("transaction queued (will be completed shortly)", "id", event["id"].(string))
//t.Logf("Transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
s.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
var err error
txHash, err = s.backend.CompleteTransaction(event["id"].(string), TestConfig.Account1.Password)
s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"]))
log.Info("contract transaction complete", "URL", "https://rinkeby.etherscan.io/tx/"+txHash.Hex())
close(completeQueuedTransaction)
}
})
_, err = vm.Run(`
var responseValue = null;
var testContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"a","type":"int256"}],"name":"double","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"}]);
var test = testContract.new(
{
from: '` + TestConfig.Account1.Address + `',
data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029',
gas: '` + strconv.Itoa(params.DefaultGas) + `'
}, function (e, contract){
if (!e) {
responseValue = contract.transactionHash
}
})
`)
require.NoError(err)
<-completeQueuedTransaction
responseValue, err := vm.Get("responseValue")
require.NoError(err, "vm.Get() failed")
response, err := responseValue.ToString()
require.NoError(err, "cannot parse result")
expectedResponse := txHash.Hex()
require.Equal(expectedResponse, response, "expected response is not returned")
}
func (s *BackendTestSuite) TestJailSendQueuedTransaction() { func (s *BackendTestSuite) TestJailSendQueuedTransaction() {
require := s.Require() require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RopstenNetworkID) s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend() defer s.StopTestBackend()
time.Sleep(TestConfig.Node.SyncSeconds * time.Second) // allow to sync time.Sleep(TestConfig.Node.SyncSeconds * time.Second) // allow to sync
jailInstance := s.backend.JailManager()
require.NotNil(jailInstance)
// log into account from which transactions will be sent // log into account from which transactions will be sent
require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)) require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
txParams := `{ txParams := `{
"from": "` + TestConfig.Account1.Address + `", "from": "` + TestConfig.Account1.Address + `",
"to": "0xf82da7547534045b4e00442bc89e16186cf8c272", "to": "` + TestConfig.Account2.Address + `",
"value": "0.000001" "value": "0.000001"
}` }`
txCompletedSuccessfully := make(chan struct{}) txCompletedSuccessfully := make(chan struct{})
txCompletedCounter := make(chan struct{})
txHashes := make(chan gethcommon.Hash) txHashes := make(chan gethcommon.Hash)
// replace transaction notification handler // replace transaction notification handler
@ -162,7 +85,6 @@ func (s *BackendTestSuite) TestJailSendQueuedTransaction() {
txCompletedSuccessfully <- struct{}{} // so that timeout is aborted txCompletedSuccessfully <- struct{}{} // so that timeout is aborted
txHashes <- txHash txHashes <- txHash
txCompletedCounter <- struct{}{}
} }
}) })
@ -253,99 +175,98 @@ func (s *BackendTestSuite) TestJailSendQueuedTransaction() {
}, },
} }
jailInstance := s.backend.JailManager()
for _, test := range tests { for _, test := range tests {
jailInstance.BaseJS(string(static.MustAsset(txSendFolder + test.file))) jailInstance.BaseJS(string(static.MustAsset(txSendFolder + test.file)))
common.PanicAfter(60*time.Second, txCompletedSuccessfully, test.name) common.PanicAfter(1*time.Minute, txCompletedSuccessfully, test.name)
jailInstance.Parse(testChatID, ``) jailInstance.Parse(testChatID, ``)
requireMessageId = test.requireMessageId requireMessageId = test.requireMessageId
for _, command := range test.commands { for _, command := range test.commands {
go func(jail common.JailManager, test testCase, command testCommand) { s.T().Logf("%s: %s", test.name, command.command)
log.Info(fmt.Sprintf("->%s: %s", test.name, command.command)) response := jailInstance.Call(testChatID, command.command, command.params)
response := jail.Call(testChatID, command.command, command.params) var txHash gethcommon.Hash
var txHash gethcommon.Hash if command.command == `["commands", "send"]` {
if command.command == `["commands", "send"]` { txHash = <-txHashes
txHash = <-txHashes }
} expectedResponse := strings.Replace(command.expectedResponse, "TX_HASH", txHash.Hex(), 1)
expectedResponse := strings.Replace(command.expectedResponse, "TX_HASH", txHash.Hex(), 1) s.Require().Equal(expectedResponse, response)
s.Equal(expectedResponse, response)
}(jailInstance, test, command)
} }
<-txCompletedCounter
} }
} }
// func (s *BackendTestSuite) TestContractDeployment() {
func (s *BackendTestSuite) TestGasEstimation() {
require := s.Require() require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RopstenNetworkID) s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend() defer s.StopTestBackend()
jailInstance := s.backend.JailManager() // Allow to sync, otherwise you'll get "Nonce too low."
require.NotNil(jailInstance) time.Sleep(TestConfig.Node.SyncSeconds * time.Second)
jailInstance.Parse(testChatID, "")
// obtain VM for a given chat (to send custom JS to jailed version of Send()) // obtain VM for a given chat (to send custom JS to jailed version of Send())
vm, err := jailInstance.JailCellVM(testChatID) jailInstance := s.backend.JailManager()
jailInstance.Parse(testChatID, "")
cell, err := jailInstance.GetJailCell(testChatID)
require.NoError(err) require.NoError(err)
// make sure you panic if transaction complete doesn't return // make sure you panic if transaction complete doesn't return
completeQueuedTransaction := make(chan struct{}, 1) completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(30*time.Second, completeQueuedTransaction, s.T().Name()) common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
var txHash gethcommon.Hash var txHash gethcommon.Hash
node.SetDefaultNodeNotificationHandler(func(jsonEvent string) { node.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
var envelope node.SignalEnvelope var envelope node.SignalEnvelope
err := json.Unmarshal([]byte(jsonEvent), &envelope) err := json.Unmarshal([]byte(jsonEvent), &envelope)
s.NoError(err, fmt.Sprintf("cannot unmarshal JSON: %s", jsonEvent)) require.NoError(err, fmt.Sprintf("cannot unmarshal JSON: %s", jsonEvent))
if envelope.Type == node.EventTransactionQueued { if envelope.Type == node.EventTransactionQueued {
event := envelope.Event.(map[string]interface{}) // Use s.* for assertions - require leaves the channel unclosed.
log.Info("transaction queued (will be completed shortly)", "id", event["id"].(string))
//t.Logf("Transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string)) event := envelope.Event.(map[string]interface{})
s.T().Logf("transaction queued and will be completed shortly, id: %v", event["id"])
s.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)) s.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
var err error var err error
txHash, err = s.backend.CompleteTransaction(event["id"].(string), TestConfig.Account1.Password) txHash, err = s.backend.CompleteTransaction(event["id"].(string), TestConfig.Account1.Password)
s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"])) if s.NoError(err, event["id"]) {
s.T().Logf("contract transaction complete, URL: %s", "https://ropsten.etherscan.io/tx/"+txHash.Hex())
}
log.Info("contract transaction complete", "URL", "https://rinkeby.etherscan.io/tx/"+txHash.Hex())
close(completeQueuedTransaction) close(completeQueuedTransaction)
} }
}) })
_, err = vm.Run(` _, err = cell.Run(`
var responseValue = null; var responseValue = null;
var testContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"a","type":"int256"}],"name":"double","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"}]); var testContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"a","type":"int256"}],"name":"double","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"}]);
var test = testContract.new( var test = testContract.new(
{ {
from: '` + TestConfig.Account1.Address + `', from: '` + TestConfig.Account1.Address + `',
data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029', data: '0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029',
gas: '` + strconv.Itoa(params.DefaultGas) + `'
}, function (e, contract){ }, function (e, contract){
if (!e) { if (!e) {
responseValue = contract.transactionHash responseValue = contract.transactionHash
} }
}) })
`) `)
s.NoError(err) require.NoError(err)
<-completeQueuedTransaction <-completeQueuedTransaction
responseValue, err := vm.Get("responseValue") responseValue, err := cell.Get("responseValue")
s.NoError(err, "vm.Get() failed") require.NoError(err)
response, err := responseValue.ToString() response, err := responseValue.ToString()
s.NoError(err, "cannot parse result") require.NoError(err)
expectedResponse := txHash.Hex() expectedResponse := txHash.Hex()
s.Equal(expectedResponse, response, "expected response is not returned") require.Equal(expectedResponse, response)
s.T().Logf("estimation complete: %s", response) s.T().Logf("estimation complete: %s", response)
} }
@ -372,7 +293,7 @@ func (s *BackendTestSuite) TestJailWhisper() {
_, err = whisperService.AddKeyPair(accountKey1.PrivateKey) _, err = whisperService.AddKeyPair(accountKey1.PrivateKey)
require.NoError(err, fmt.Sprintf("identity not injected: %v", accountKey1Hex)) require.NoError(err, fmt.Sprintf("identity not injected: %v", accountKey1Hex))
if ok, err := whisperAPI.HasKeyPair(accountKey1Hex); err != nil || !ok { if ok := whisperAPI.HasKeyPair(context.Background(), accountKey1Hex); !ok {
require.FailNow(fmt.Sprintf("identity not injected: %v", accountKey1Hex)) require.FailNow(fmt.Sprintf("identity not injected: %v", accountKey1Hex))
} }
@ -384,7 +305,7 @@ func (s *BackendTestSuite) TestJailWhisper() {
_, err = whisperService.AddKeyPair(accountKey2.PrivateKey) _, err = whisperService.AddKeyPair(accountKey2.PrivateKey)
require.NoError(err, fmt.Sprintf("identity not injected: %v", accountKey2Hex)) require.NoError(err, fmt.Sprintf("identity not injected: %v", accountKey2Hex))
if ok, err := whisperAPI.HasKeyPair(accountKey2Hex); err != nil || !ok { if ok := whisperAPI.HasKeyPair(context.Background(), accountKey2Hex); !ok {
require.FailNow(fmt.Sprintf("identity not injected: %v", accountKey2Hex)) require.FailNow(fmt.Sprintf("identity not injected: %v", accountKey2Hex))
} }
@ -694,11 +615,12 @@ func (s *BackendTestSuite) TestJailWhisper() {
return web3.toHex(randInt); return web3.toHex(randInt);
}; };
`) `)
vm, err := jailInstance.JailCellVM(testCaseKey)
cell, err := jailInstance.GetJailCell(testCaseKey)
require.NoError(err, "cannot get VM") require.NoError(err, "cannot get VM")
// post messages // post messages
if _, err := vm.Run(testCase.testCode); err != nil { if _, err := cell.Run(testCase.testCode); err != nil {
require.Fail(err.Error()) require.Fail(err.Error())
return return
} }
@ -708,10 +630,10 @@ func (s *BackendTestSuite) TestJailWhisper() {
} }
// update installed filters // update installed filters
filterId, err := vm.Get("filterId") filterId, err := cell.Get("filterId")
require.NoError(err, "cannot get filterId") require.NoError(err, "cannot get filterId")
filterName, err := vm.Get("filterName") filterName, err := cell.Get("filterName")
require.NoError(err, "cannot get filterName") require.NoError(err, "cannot get filterName")
if _, ok := installedFilters[filterName.String()]; !ok { if _, ok := installedFilters[filterName.String()]; !ok {
@ -726,8 +648,10 @@ func (s *BackendTestSuite) TestJailWhisper() {
for testKey, filter := range installedFilters { for testKey, filter := range installedFilters {
if filter != "" { if filter != "" {
s.T().Logf("filter found: %v", filter) s.T().Logf("filter found: %v", filter)
for _, message := range whisperAPI.GetNewSubscriptionMessages(filter) { messages, err := whisperAPI.GetFilterMessages(filter)
s.T().Logf("message found: %s", gethcommon.FromHex(message.Payload)) require.NoError(err)
for _, message := range messages {
s.T().Logf("message found: %s", string(message.Payload))
passedTests[testKey] = true passedTests[testKey] = true
} }
} }
@ -739,3 +663,134 @@ func (s *BackendTestSuite) TestJailWhisper() {
} }
} }
} }
func (s *BackendTestSuite) TestJailVMPersistence() {
require := s.Require()
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
// log into account from which transactions will be sent
err := s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)
require.NoError(err, "cannot select account: %v", TestConfig.Account1.Address)
type testCase struct {
command string
params string
validator func(response string) error
}
var testCases = []testCase{
{
`["sendTestTx"]`,
`{"amount": "0.000001", "from": "` + TestConfig.Account1.Address + `"}`,
func(response string) error {
if strings.Contains(response, "error") {
return fmt.Errorf("unexpected response: %v", response)
}
return nil
},
},
{
`["sendTestTx"]`,
`{"amount": "0.000002", "from": "` + TestConfig.Account1.Address + `"}`,
func(response string) error {
if strings.Contains(response, "error") {
return fmt.Errorf("unexpected response: %v", response)
}
return nil
},
},
{
`["ping"]`,
`{"pong": "Ping1", "amount": 0.42}`,
func(response string) error {
expectedResponse := `{"result": "Ping1"}`
if response != expectedResponse {
return fmt.Errorf("unexpected response, expected: %v, got: %v", expectedResponse, response)
}
return nil
},
},
{
`["ping"]`,
`{"pong": "Ping2", "amount": 0.42}`,
func(response string) error {
expectedResponse := `{"result": "Ping2"}`
if response != expectedResponse {
return fmt.Errorf("unexpected response, expected: %v, got: %v", expectedResponse, response)
}
return nil
},
},
}
jailInstance := s.backend.JailManager()
jailInstance.BaseJS(string(static.MustAsset("testdata/jail/status.js")))
parseResult := jailInstance.Parse(testChatID, `
var total = 0;
_status_catalog['ping'] = function(params) {
total += params.amount;
return params.pong;
}
_status_catalog['sendTestTx'] = function(params) {
var amount = params.amount;
var transaction = {
"from": params.from,
"to": "`+TestConfig.Account2.Address+`",
"value": web3.toWei(amount, "ether")
};
web3.eth.sendTransaction(transaction, function (error, result) {
console.log("eth.sendTransaction callback: 'total' variable (is it updated by concurrent goroutine?): " + total);
if(!error)
total += amount;
});
}
`)
require.NotContains(parseResult, "error", "further will fail if initial parsing failed")
var wg sync.WaitGroup
node.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
var envelope node.SignalEnvelope
if err := json.Unmarshal([]byte(jsonEvent), &envelope); err != nil {
s.T().Errorf("cannot unmarshal event's JSON: %s", jsonEvent)
return
}
if envelope.Type == node.EventTransactionQueued {
event := envelope.Event.(map[string]interface{})
s.T().Logf("Transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
time.Sleep(1 * time.Second)
//if err := geth.DiscardTransaction(event["id"].(string)); err != nil {
// t.Errorf("cannot discard: %v", err)
// progress <- "tx discarded"
// return
//}
//var txHash common.Hash
txHash, err := s.backend.CompleteTransaction(event["id"].(string), TestConfig.Account1.Password)
require.NoError(err, "cannot complete queued transaction[%v]: %v", event["id"], err)
s.T().Logf("Transaction complete: https://ropsten.etherscan.io/tx/%s", txHash.Hex())
}
})
// run commands concurrently
for _, tc := range testCases {
wg.Add(1)
go func(tc testCase) {
s.T().Logf("CALL START: %v %v", tc.command, tc.params)
response := jailInstance.Call(testChatID, tc.command, tc.params)
if err := tc.validator(response); err != nil {
s.T().Errorf("failed test validation: %v, err: %v", tc.command, err)
}
s.T().Logf("CALL END: %v %v", tc.command, tc.params)
wg.Done()
}(tc)
}
common.PanicAfter(10*time.Second, nil, "test timed out")
wg.Wait()
}

View File

@ -148,6 +148,8 @@ func (s *BackendTestSuite) TestNodeStartStop() {
require.True(s.backend.IsNodeRunning()) require.True(s.backend.IsNodeRunning())
} }
// FIXME(tiabc): There's also a test with the same name in geth/node/rpc_test.go
// so this test should only check StatusBackend logic with a mocked version of the underlying NodeManager.
func (s *BackendTestSuite) TestCallRPC() { func (s *BackendTestSuite) TestCallRPC() {
require := s.Require() require := s.Require()
require.NotNil(s.backend) require.NotNil(s.backend)
@ -184,7 +186,7 @@ func (s *BackendTestSuite) TestCallRPC() {
{ {
`{"jsonrpc":"2.0","method":"shh_version","params":[],"id":67}`, `{"jsonrpc":"2.0","method":"shh_version","params":[],"id":67}`,
func(resultJSON string) { func(resultJSON string) {
expected := `{"jsonrpc":"2.0","id":67,"result":"0x5"}` + "\n" expected := `{"jsonrpc":"2.0","id":67,"result":"5.0"}` + "\n"
s.Equal(expected, resultJSON) s.Equal(expected, resultJSON)
s.T().Log("shh_version: ", resultJSON) s.T().Log("shh_version: ", resultJSON)
progress <- struct{}{} progress <- struct{}{}
@ -227,6 +229,8 @@ func (s *BackendTestSuite) TestCallRPC() {
} }
} }
// FIXME(tiabc): There's also a test with the same name in geth/node/manager_test.go
// so this test should only check StatusBackend logic with a mocked version of the underlying NodeManager.
func (s *BackendTestSuite) TestRaceConditions() { func (s *BackendTestSuite) TestRaceConditions() {
require := s.Require() require := s.Require()
require.NotNil(s.backend) require.NotNil(s.backend)
@ -382,6 +386,8 @@ func (s *BackendTestSuite) TestRaceConditions() {
} }
} }
// FIXME(tiabc): There's also a test with the same name in geth/node/manager_test.go
// so this test should only check StatusBackend logic with a mocked version of the underlying NodeManager.
func (s *BackendTestSuite) TestNetworkSwitching() { func (s *BackendTestSuite) TestNetworkSwitching() {
require := s.Require() require := s.Require()
require.NotNil(s.backend) require.NotNil(s.backend)
@ -423,6 +429,8 @@ func (s *BackendTestSuite) TestNetworkSwitching() {
<-nodeStopped <-nodeStopped
} }
// FIXME(tiabc): There's also a test with the same name in geth/node/manager_test.go
// so this test should only check StatusBackend logic with a mocked version of the underlying NodeManager.
func (s *BackendTestSuite) TestResetChainData() { func (s *BackendTestSuite) TestResetChainData() {
require := s.Require() require := s.Require()
require.NotNil(s.backend) require.NotNil(s.backend)
@ -442,6 +450,8 @@ func (s *BackendTestSuite) TestResetChainData() {
FirstBlockHash(require, s.backend.NodeManager(), "0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177") FirstBlockHash(require, s.backend.NodeManager(), "0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177")
} }
// FIXME(tiabc): There's also a test with the same name in geth/node/manager_test.go
// so this test should only check StatusBackend logic with a mocked version of the underlying NodeManager.
func (s *BackendTestSuite) TestRestartNode() { func (s *BackendTestSuite) TestRestartNode() {
require := s.Require() require := s.Require()
require.NotNil(s.backend) require.NotNil(s.backend)

View File

@ -18,6 +18,7 @@ import (
. "github.com/status-im/status-go/geth/testing" . "github.com/status-im/status-go/geth/testing"
) )
// FIXME(tiabc): Sometimes it fails due to "no suitable peers found".
func (s *BackendTestSuite) TestSendContractTx() { func (s *BackendTestSuite) TestSendContractTx() {
require := s.Require() require := s.Require()
require.NotNil(s.backend) require.NotNil(s.backend)
@ -36,7 +37,7 @@ func (s *BackendTestSuite) TestSendContractTx() {
// make sure you panic if transaction complete doesn't return // make sure you panic if transaction complete doesn't return
completeQueuedTransaction := make(chan struct{}, 10) completeQueuedTransaction := make(chan struct{}, 10)
common.PanicAfter(20*time.Second, completeQueuedTransaction, s.T().Name()) common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
var txHash = gethcommon.Hash{} var txHash = gethcommon.Hash{}
@ -114,7 +115,7 @@ func (s *BackendTestSuite) TestSendEtherTx() {
// make sure you panic if transaction complete doesn't return // make sure you panic if transaction complete doesn't return
completeQueuedTransaction := make(chan struct{}, 1) completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(20*time.Second, completeQueuedTransaction, s.T().Name()) common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
var txHash = gethcommon.Hash{} var txHash = gethcommon.Hash{}
@ -185,7 +186,7 @@ func (s *BackendTestSuite) TestDoubleCompleteQueuedTransactions() {
// make sure you panic if transaction complete doesn't return // make sure you panic if transaction complete doesn't return
completeQueuedTransaction := make(chan struct{}, 1) completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(20*time.Second, completeQueuedTransaction, s.T().Name()) common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
var txID string var txID string
@ -269,7 +270,7 @@ func (s *BackendTestSuite) TestDiscardQueuedTransaction() {
// make sure you panic if transaction complete doesn't return // make sure you panic if transaction complete doesn't return
completeQueuedTransaction := make(chan struct{}, 1) completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(30*time.Second, completeQueuedTransaction, s.T().Name()) common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
var txID string var txID string
@ -573,7 +574,7 @@ func (s *BackendTestSuite) TestDiscardMultipleQueuedTransactions() {
select { select {
case <-allTestTxDiscarded: case <-allTestTxDiscarded:
// pass // pass
case <-time.After(30 * time.Second): case <-time.After(1 * time.Minute):
s.Fail("test timed out") s.Fail("test timed out")
return return
} }

View File

@ -16,8 +16,6 @@ import (
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"github.com/status-im/status-go/geth/params" "github.com/status-im/status-go/geth/params"
"github.com/status-im/status-go/static" "github.com/status-im/status-go/static"
"fknsrs.biz/p/ottoext/loop"
) )
// errors // errors
@ -173,28 +171,12 @@ type TxQueueManager interface {
DiscardTransactions(ids string) map[string]RawDiscardTransactionResult DiscardTransactions(ids string) map[string]RawDiscardTransactionResult
} }
// JailExecutor defines an interface which exposes method to be executed
// against a Jail vm.
type JailExecutor interface {
// Run exist so we are able to execute js code on pure otto.VM without runing
// it on the event loop.
Run(string) (otto.Value, error)
// Exec exists for the purpose to execute has normal on the event loop provided by
// ottoext.
Exec(string) (otto.Value, error)
// Fetch calls the underlying FetchAPI which makes http request
// to desired path. (See https://developer.mozilla.org/en/docs/Web/API/Fetch_API).
Fetch(string, func(otto.Value)) (otto.Value, error)
}
// JailCell represents single jail cell, which is basically a JavaScript VM. // JailCell represents single jail cell, which is basically a JavaScript VM.
type JailCell interface { type JailCell interface {
CellVM() *otto.Otto Set(string, interface{}) error
CellLoop() *loop.Loop Get(string) (otto.Value, error)
Executor() JailExecutor Run(string) (otto.Value, error)
Copy() (JailCell, error) RunOnLoop(string) (otto.Value, error)
} }
// JailManager defines methods for managing jailed environments // JailManager defines methods for managing jailed environments
@ -208,10 +190,10 @@ type JailManager interface {
Call(chatID string, path string, args string) string Call(chatID string, path string, args string) string
// NewJailCell initializes and returns jail cell // NewJailCell initializes and returns jail cell
NewJailCell(id string) JailCell NewJailCell(id string) (JailCell, error)
// JailCellVM returns instance of Otto VM (which is persisted w/i jail cell) by chatID // GetJailCell returns instance of JailCell (which is persisted w/i jail cell) by chatID
JailCellVM(chatID string) (*otto.Otto, error) GetJailCell(chatID string) (JailCell, error)
// BaseJS allows to setup initial JavaScript to be loaded on each jail.Parse() // BaseJS allows to setup initial JavaScript to be loaded on each jail.Parse()
BaseJS(js string) BaseJS(js string)

View File

@ -0,0 +1,52 @@
package console
import (
"fmt"
"io"
"strings"
"github.com/robertkrimen/otto"
"github.com/status-im/status-go/geth/node"
)
// Write provides the base function to write data to the underline writer
// for the underline otto vm.
func Write(fn otto.FunctionCall, w io.Writer, consoleEventName string) otto.Value {
node.SendSignal(node.SignalEnvelope{
Type: consoleEventName,
Event: convertArgs(fn.ArgumentList),
})
// Next print out the giving values.
fmt.Fprintf(w, "%s: %s", consoleEventName, formatForConsole(fn.ArgumentList))
return otto.UndefinedValue()
}
// formatForConsole handles conversion of giving otto.Values into
// string counter part.
func formatForConsole(argumentList []otto.Value) string {
output := []string{}
for _, argument := range argumentList {
output = append(output, fmt.Sprintf("%v", argument))
}
return strings.Join(output, " ")
}
// convertArgs attempts to convert otto.Values into proper go types else
// uses original.
func convertArgs(argumentList []otto.Value) []interface{} {
var items []interface{}
for _, arg := range argumentList {
realArg, err := arg.Export()
if err != nil {
items = append(items, arg)
continue
}
items = append(items, realArg)
}
return items
}

View File

@ -0,0 +1,95 @@
package console_test
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"testing"
"github.com/robertkrimen/otto"
"github.com/status-im/status-go/geth/jail/console"
"github.com/status-im/status-go/geth/node"
"github.com/stretchr/testify/suite"
)
// TestConsole validates the behaviour of giving conole extensions.
func TestConsole(t *testing.T) {
suite.Run(t, new(ConsoleTestSuite))
}
type ConsoleTestSuite struct {
suite.Suite
vm *otto.Otto
}
func (s *ConsoleTestSuite) SetupTest() {
require := s.Require()
vm := otto.New()
require.NotNil(vm)
s.vm = vm
}
// TestConsoleLog will validate the operations of the console.log extension
// for the otto vm.
func (s *ConsoleTestSuite) TestConsoleLog() {
require := s.Require()
written := "Bob Marley"
var customWriter bytes.Buffer
err := s.vm.Set("console", map[string]interface{}{
"log": func(fn otto.FunctionCall) otto.Value {
return console.Write(fn, &customWriter, "vm.console")
},
})
require.NoError(err)
_, err = s.vm.Run(fmt.Sprintf(`console.log(%q);`, written))
require.NoError(err)
require.Equal(written, strings.TrimPrefix(customWriter.String(), "vm.console: "))
}
// TestObjectLogging will validate the operations of the console.log extension
// when capturing objects declared from javascript.
func (s *ConsoleTestSuite) TestObjectLogging() {
require := s.Require()
var customWriter bytes.Buffer
node.SetDefaultNodeNotificationHandler(func(event string) {
var eventReceived struct {
Type string `json:"type"`
Event []struct {
Age int `json:"age"`
Name string `json:"name"`
} `json:"event"`
}
err := json.Unmarshal([]byte(event), &eventReceived)
require.NoError(err)
require.Equal(eventReceived.Type, "vm.console")
require.NotEmpty(eventReceived.Event)
objectReceived := eventReceived.Event[0]
require.Equal(objectReceived.Age, 24)
require.Equal(objectReceived.Name, "bob")
})
err := s.vm.Set("console", map[string]interface{}{
"log": func(fn otto.FunctionCall) otto.Value {
return console.Write(fn, &customWriter, "vm.console")
},
})
require.NoError(err)
_, err = s.vm.Run(`
var person = {name:"bob", age:24}
console.log(person);
`)
require.NoError(err)
require.NotEmpty(&customWriter)
}

View File

@ -1,33 +1,48 @@
package jail package jail
import ( import (
"os"
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"github.com/status-im/status-go/geth/jail/console"
"github.com/status-im/status-go/geth/node" "github.com/status-im/status-go/geth/node"
) )
// signals
const ( const (
EventLocalStorageSet = "local_storage.set" EventLocalStorageSet = "local_storage.set"
EventSendMessage = "jail.send_message" EventSendMessage = "jail.send_message"
EventShowSuggestions = "jail.show_suggestions" EventShowSuggestions = "jail.show_suggestions"
LocalStorageMaxDataLen = 256
// EventConsoleLog defines the event type for the console.log call.
eventConsoleLog = "vm.console.log"
) )
// registerHandlers augments and transforms a given jail cell's underlying VM, // registerHandlers augments and transforms a given jail cell's underlying VM,
// by adding and replacing method handlers. // by adding and replacing method handlers.
func registerHandlers(jail *Jail, vm *otto.Otto, chatID string) (err error) { func registerHandlers(jail *Jail, cell *JailCell, chatID string) error {
jeth, err := vm.Get("jeth") jeth, err := cell.Get("jeth")
if err != nil { if err != nil {
return err return err
} }
registerHandler := jeth.Object().Set registerHandler := jeth.Object().Set
if err = registerHandler("console", map[string]interface{}{
"log": func(fn otto.FunctionCall) otto.Value {
return console.Write(fn, os.Stdout, eventConsoleLog)
},
}); err != nil {
return err
}
// register send handler // register send handler
if err = registerHandler("send", makeSendHandler(jail, chatID)); err != nil { if err = registerHandler("send", makeSendHandler(jail)); err != nil {
return err return err
} }
// register sendAsync handler // register sendAsync handler
if err = registerHandler("sendAsync", makeSendHandler(jail, chatID)); err != nil { if err = registerHandler("sendAsync", makeSendHandler(jail)); err != nil {
return err return err
} }
@ -37,27 +52,46 @@ func registerHandlers(jail *Jail, vm *otto.Otto, chatID string) (err error) {
} }
// define localStorage // define localStorage
if err = vm.Set("localStorage", struct{}{}); err != nil { if err = cell.Set("localStorage", struct{}{}); err != nil {
return return err
} }
// register localStorage.set handler // register localStorage.set handler
localStorage, err := vm.Get("localStorage") localStorage, err := cell.Get("localStorage")
if err != nil { if err != nil {
return return err
} }
if err = localStorage.Object().Set("set", makeLocalStorageSetHandler(chatID)); err != nil { if err = localStorage.Object().Set("set", makeLocalStorageSetHandler(chatID)); err != nil {
return return err
}
// register sendMessage/showSuggestions handlers
if err = cell.Set("statusSignals", struct{}{}); err != nil {
return err
}
statusSignals, err := cell.Get("statusSignals")
if err != nil {
return err
}
registerHandler = statusSignals.Object().Set
if err = registerHandler("sendMessage", makeSendMessageHandler(chatID)); err != nil {
return err
}
if err = registerHandler("showSuggestions", makeShowSuggestionsHandler(chatID)); err != nil {
return err
} }
return nil return nil
} }
// makeSendHandler returns jeth.send() and jeth.sendAsync() handler // makeSendHandler returns jeth.send() and jeth.sendAsync() handler
func makeSendHandler(jail *Jail, chatID string) func(call otto.FunctionCall) (response otto.Value) { func makeSendHandler(jail *Jail) func(call otto.FunctionCall) (response otto.Value) {
return func(call otto.FunctionCall) (response otto.Value) { return jail.Send
return jail.Send(chatID, call)
}
} }
// makeJethIsConnectedHandler returns jeth.isConnected() handler // makeJethIsConnectedHandler returns jeth.isConnected() handler
@ -65,19 +99,19 @@ func makeJethIsConnectedHandler(jail *Jail) func(call otto.FunctionCall) (respon
return func(call otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value {
client, err := jail.requestManager.RPCClient() client, err := jail.requestManager.RPCClient()
if err != nil { if err != nil {
return newErrorResponse(call, -32603, err.Error(), nil) return newErrorResponse(call.Otto, -32603, err.Error(), nil)
} }
var netListeningResult bool var netListeningResult bool
if err := client.Call(&netListeningResult, "net_listening"); err != nil { if err := client.Call(&netListeningResult, "net_listening"); err != nil {
return newErrorResponse(call, -32603, err.Error(), nil) return newErrorResponse(call.Otto, -32603, err.Error(), nil)
} }
if !netListeningResult { if !netListeningResult {
return newErrorResponse(call, -32603, node.ErrNoRunningNode.Error(), nil) return newErrorResponse(call.Otto, -32603, node.ErrNoRunningNode.Error(), nil)
} }
return newResultResponse(call, true) return newResultResponse(call.Otto, true)
} }
} }
@ -91,9 +125,6 @@ type LocalStorageSetEvent struct {
func makeLocalStorageSetHandler(chatID string) func(call otto.FunctionCall) (response otto.Value) { func makeLocalStorageSetHandler(chatID string) func(call otto.FunctionCall) (response otto.Value) {
return func(call otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value {
data := call.Argument(0).String() data := call.Argument(0).String()
if len(data) > LocalStorageMaxDataLen { // cap input string
data = data[:LocalStorageMaxDataLen]
}
node.SendSignal(node.SignalEnvelope{ node.SendSignal(node.SignalEnvelope{
Type: EventLocalStorageSet, Type: EventLocalStorageSet,
@ -103,7 +134,7 @@ func makeLocalStorageSetHandler(chatID string) func(call otto.FunctionCall) (res
}, },
}) })
return newResultResponse(call, true) return newResultResponse(call.Otto, true)
} }
} }
@ -125,7 +156,7 @@ func makeSendMessageHandler(chatID string) func(call otto.FunctionCall) (respons
}, },
}) })
return newResultResponse(call, true) return newResultResponse(call.Otto, true)
} }
} }
@ -147,6 +178,6 @@ func makeShowSuggestionsHandler(chatID string) func(call otto.FunctionCall) (res
}, },
}) })
return newResultResponse(call, true) return newResultResponse(call.Otto, true)
} }
} }

View File

@ -5,25 +5,17 @@ import (
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"time"
"github.com/eapache/go-resiliency/semaphore"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"github.com/status-im/status-go/geth/common" "github.com/status-im/status-go/geth/common"
"github.com/status-im/status-go/static" "github.com/status-im/status-go/static"
"fknsrs.biz/p/ottoext/fetch"
"fknsrs.biz/p/ottoext/loop" "fknsrs.biz/p/ottoext/loop"
"fknsrs.biz/p/ottoext/timers"
)
const (
// JailCellRequestTimeout seconds before jailed request times out
JailCellRequestTimeout = 60
) )
// FIXME(tiabc): Get rid of this global variable. Move it to a constructor or initialization.
var web3JSCode = static.MustAsset("scripts/web3.js") var web3JSCode = static.MustAsset("scripts/web3.js")
// errors // errors
@ -31,160 +23,101 @@ var (
ErrInvalidJail = errors.New("jail environment is not properly initialized") ErrInvalidJail = errors.New("jail environment is not properly initialized")
) )
// JailCell represents single jail cell, which is basically a JavaScript VM.
type JailCell struct {
id string
vm *otto.Otto
lo *loop.Loop
sem *semaphore.Semaphore
}
// newJailCell encapsulates what we need to create a new jailCell from the
// provided vm and eventloop instance.
func newJailCell(id string, vm *otto.Otto, lo *loop.Loop) (*JailCell, error) {
// Register fetch provider from ottoext.
if err := fetch.Define(vm, lo); err != nil {
return nil, err
}
// Register event loop for timers.
if err := timers.Define(vm, lo); err != nil {
return nil, err
}
return &JailCell{
id: id,
vm: vm,
lo: lo,
sem: semaphore.New(1, JailCellRequestTimeout*time.Second),
}, nil
}
// Jail represents jailed environment inside of which we hold multiple cells. // Jail represents jailed environment inside of which we hold multiple cells.
// Each cell is a separate JavaScript VM. // Each cell is a separate JavaScript VM.
type Jail struct { type Jail struct {
sync.RWMutex sync.RWMutex
requestManager *RequestManager requestManager *RequestManager
cells map[string]common.JailCell // jail supports running many isolated instances of jailed runtime cells map[string]*JailCell // jail supports running many isolated instances of jailed runtime
baseJSCode string // JavaScript used to initialize all new cells with baseJSCode string // JavaScript used to initialize all new cells with
} }
// Copy returns a new JailCell instance with a new eventloop runtime associated with // New returns new Jail environment.
// the given cell.
func (cell *JailCell) Copy() (common.JailCell, error) {
vmCopy := cell.vm.Copy()
return newJailCell(cell.id, vmCopy, loop.New(vmCopy))
}
// Fetch attempts to call the underline Fetch API added through the
// ottoext package.
func (cell *JailCell) Fetch(url string, callback func(otto.Value)) (otto.Value, error) {
if err := cell.vm.Set("__captureFetch", callback); err != nil {
return otto.UndefinedValue(), err
}
return cell.Exec(`fetch("` + url + `").then(function(response){
__captureFetch({
"url": response.url,
"type": response.type,
"body": response.text(),
"status": response.status,
"headers": response.headers,
});
});
`)
}
// Exec evaluates the giving js string on the associated vm loop returning
// an error.
func (cell *JailCell) Exec(val string) (otto.Value, error) {
res, err := cell.vm.Run(val)
if err != nil {
return res, err
}
return res, cell.lo.Run()
}
// Run evaluates the giving js string on the associated vm llop.
func (cell *JailCell) Run(val string) (otto.Value, error) {
return cell.vm.Run(val)
}
// CellLoop returns the ottoext.Loop instance which provides underline timeout/setInternval
// event runtime for the Jail vm.
func (cell *JailCell) CellLoop() *loop.Loop {
return cell.lo
}
// Executor returns a structure which implements the common.JailExecutor.
func (cell *JailCell) Executor() common.JailExecutor {
return cell
}
// CellVM returns the associated otto.Vm connect to the giving cell.
func (cell *JailCell) CellVM() *otto.Otto {
return cell.vm
}
// New returns new Jail environment
func New(nodeManager common.NodeManager) *Jail { func New(nodeManager common.NodeManager) *Jail {
return &Jail{ return &Jail{
cells: make(map[string]*JailCell),
requestManager: NewRequestManager(nodeManager), requestManager: NewRequestManager(nodeManager),
cells: make(map[string]common.JailCell),
} }
} }
// BaseJS allows to setup initial JavaScript to be loaded on each jail.Parse() // BaseJS allows to setup initial JavaScript to be loaded on each jail.Parse().
func (jail *Jail) BaseJS(js string) { func (jail *Jail) BaseJS(js string) {
jail.baseJSCode = js jail.baseJSCode = js
} }
// NewJailCell initializes and returns jail cell // NewJailCell initializes and returns jail cell.
func (jail *Jail) NewJailCell(id string) common.JailCell { func (jail *Jail) NewJailCell(id string) (common.JailCell, error) {
if jail == nil {
return nil, ErrInvalidJail
}
vm := otto.New() vm := otto.New()
newJail, err := newJailCell(id, vm, loop.New(vm)) newJail, err := newJailCell(id, vm, loop.New(vm))
if err != nil { if err != nil {
//TODO(alex): Should we really panic here, his there return nil, err
// a better way. Think on it.
panic(err)
} }
return newJail jail.Lock()
jail.cells[id] = newJail
jail.Unlock()
return newJail, nil
}
// GetJailCell returns the associated *JailCell for the provided chatID.
func (jail *Jail) GetJailCell(chatID string) (common.JailCell, error) {
return jail.GetCell(chatID)
}
// GetCell returns the associated *JailCell for the provided chatID.
func (jail *Jail) GetCell(chatID string) (*JailCell, error) {
jail.RLock()
defer jail.RUnlock()
cell, ok := jail.cells[chatID]
if !ok {
return nil, fmt.Errorf("cell[%s] doesn't exist", chatID)
}
return cell, nil
} }
// Parse creates a new jail cell context, with the given chatID as identifier. // Parse creates a new jail cell context, with the given chatID as identifier.
// New context executes provided JavaScript code, right after the initialization. // New context executes provided JavaScript code, right after the initialization.
func (jail *Jail) Parse(chatID string, js string) string { func (jail *Jail) Parse(chatID string, js string) string {
var err error
if jail == nil { if jail == nil {
return makeError(ErrInvalidJail.Error()) return makeError(ErrInvalidJail.Error())
} }
jail.Lock() var err error
defer jail.Unlock() var jcell *JailCell
jail.cells[chatID] = jail.NewJailCell(chatID) if jcell, err = jail.GetCell(chatID); err != nil {
vm := jail.cells[chatID].CellVM() if _, mkerr := jail.NewJailCell(chatID); mkerr != nil {
return makeError(mkerr.Error())
}
initJjs := jail.baseJSCode + ";" jcell, _ = jail.GetCell(chatID)
if _, err = vm.Run(initJjs); err != nil {
return makeError(err.Error())
} }
// init jeth and its handlers // init jeth and its handlers
if err = vm.Set("jeth", struct{}{}); err != nil { if err = jcell.Set("jeth", struct{}{}); err != nil {
return makeError(err.Error()) return makeError(err.Error())
} }
if err = registerHandlers(jail, vm, chatID); err != nil {
if err = registerHandlers(jail, jcell, chatID); err != nil {
return makeError(err.Error())
}
initJs := jail.baseJSCode + ";"
if _, err = jcell.Run(initJs); err != nil {
return makeError(err.Error()) return makeError(err.Error())
} }
// sendMessage/showSuggestions handlers // sendMessage/showSuggestions handlers
vm.Set("statusSignals", struct{}{}) jcell.Set("statusSignals", struct{}{})
statusSignals, _ := vm.Get("statusSignals") statusSignals, _ := jcell.Get("statusSignals")
statusSignals.Object().Set("sendMessage", makeSendMessageHandler(chatID)) statusSignals.Object().Set("sendMessage", makeSendMessageHandler(chatID))
statusSignals.Object().Set("showSuggestions", makeShowSuggestionsHandler(chatID)) statusSignals.Object().Set("showSuggestions", makeShowSuggestionsHandler(chatID))
@ -196,11 +129,11 @@ func (jail *Jail) Parse(chatID string, js string) string {
return new Bignumber(val); return new Bignumber(val);
} }
` + js + "; var catalog = JSON.stringify(_status_catalog);" ` + js + "; var catalog = JSON.stringify(_status_catalog);"
if _, err = vm.Run(jjs); err != nil { if _, err = jcell.Run(jjs); err != nil {
return makeError(err.Error()) return makeError(err.Error())
} }
res, err := vm.Get("catalog") res, err := jcell.Get("catalog")
if err != nil { if err != nil {
return makeError(err.Error()) return makeError(err.Error())
} }
@ -208,54 +141,34 @@ func (jail *Jail) Parse(chatID string, js string) string {
return makeResult(res.String(), err) return makeResult(res.String(), err)
} }
// Call executes given JavaScript function w/i a jail cell context identified by the chatID. // Call executes the `call` function w/i a jail cell context identified by the chatID.
// Jail cell is clonned before call is executed i.e. all calls execute w/i their own contexts. // Jail cell is clonned before call is executed i.e. all calls execute w/i their own contexts.
func (jail *Jail) Call(chatID string, path string, args string) string { func (jail *Jail) Call(chatID string, path string, args string) string {
jail.RLock() jcell, err := jail.GetCell(chatID)
cell, ok := jail.cells[chatID]
if !ok {
jail.RUnlock()
return makeError(fmt.Sprintf("Cell[%s] doesn't exist.", chatID))
}
jail.RUnlock()
// Due to the new timer assigned we need to clone existing cell to allow
// unique cell runtime and eventloop context.
cellCopy, err := cell.Copy()
if err != nil { if err != nil {
return makeError(err.Error()) return makeError(err.Error())
} }
// isolate VM to allow concurrent access res, err := jcell.Call("call", nil, path, args)
vm := cellCopy.CellVM()
res, err := vm.Call("call", nil, path, args) // WARNING(influx6): We can have go-routine leakage due to continous call to this method
// and the call to cell.CellLoop().Run() due to improper usage, let's keep this
// in sight if things ever go wrong here.
// Due to the new event loop provided by ottoext.
// We need to ensure that all possible calls to internal setIntervals/SetTimeouts/SetImmediate
// work by lunching the loop.Run() method.
// Needs to be done in a go-routine.
go jcell.lo.Run()
return makeResult(res.String(), err) return makeResult(res.String(), err)
} }
// JailCellVM returns instance of Otto VM (which is persisted w/i jail cell) by chatID
func (jail *Jail) JailCellVM(chatID string) (*otto.Otto, error) {
if jail == nil {
return nil, ErrInvalidJail
}
jail.RLock()
defer jail.RUnlock()
cell, ok := jail.cells[chatID]
if !ok {
return nil, fmt.Errorf("cell[%s] doesn't exist", chatID)
}
return cell.CellVM(), nil
}
// Send will serialize the first argument, send it to the node and returns the response. // Send will serialize the first argument, send it to the node and returns the response.
// nolint: errcheck, unparam // nolint: errcheck, unparam
func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Value) { func (jail *Jail) Send(call otto.FunctionCall) (response otto.Value) {
client, err := jail.requestManager.RPCClient() client, err := jail.requestManager.RPCClient()
if err != nil { if err != nil {
return newErrorResponse(call, -32603, err.Error(), nil) return newErrorResponse(call.Otto, -32603, err.Error(), nil)
} }
// Remarshal the request into a Go value. // Remarshal the request into a Go value.
@ -290,7 +203,7 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
txHash, err := jail.requestManager.ProcessSendTransactionRequest(call.Otto, req) txHash, err := jail.requestManager.ProcessSendTransactionRequest(call.Otto, req)
resp.Set("result", txHash.Hex()) resp.Set("result", txHash.Hex())
if err != nil { if err != nil {
resp = newErrorResponse(call, -32603, err.Error(), &req.ID).Object() resp = newErrorResponse(call.Otto, -32603, err.Error(), &req.ID).Object()
} }
resps.Call("push", resp) resps.Call("push", resp)
continue continue
@ -301,7 +214,7 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
// so that no more than one client (per cell) can enter // so that no more than one client (per cell) can enter
messageID, err := jail.requestManager.PreProcessRequest(call.Otto, req) messageID, err := jail.requestManager.PreProcessRequest(call.Otto, req)
if err != nil { if err != nil {
return newErrorResponse(call, -32603, err.Error(), nil) return newErrorResponse(call.Otto, -32603, err.Error(), nil)
} }
errc := make(chan error, 1) errc := make(chan error, 1)
@ -321,7 +234,7 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
} else { } else {
resultVal, callErr := JSON.Call("parse", string(result)) resultVal, callErr := JSON.Call("parse", string(result))
if callErr != nil { if callErr != nil {
resp = newErrorResponse(call, -32603, callErr.Error(), &req.ID).Object() resp = newErrorResponse(call.Otto, -32603, callErr.Error(), &req.ID).Object()
} else { } else {
resp.Set("result", resultVal) resp.Set("result", resultVal)
} }
@ -332,7 +245,7 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
"message": err.Error(), "message": err.Error(),
}) })
default: default:
resp = newErrorResponse(call, -32603, err.Error(), &req.ID).Object() resp = newErrorResponse(call.Otto, -32603, err.Error(), &req.ID).Object()
} }
resps.Call("push", resp) resps.Call("push", resp)
@ -354,16 +267,16 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
return response return response
} }
func newErrorResponse(call otto.FunctionCall, code int, msg string, id interface{}) otto.Value { func newErrorResponse(otto *otto.Otto, code int, msg string, id interface{}) otto.Value {
// Bundle the error into a JSON RPC call response // Bundle the error into a JSON RPC call response
m := map[string]interface{}{"jsonrpc": "2.0", "id": id, "error": map[string]interface{}{"code": code, msg: msg}} m := map[string]interface{}{"jsonrpc": "2.0", "id": id, "error": map[string]interface{}{"code": code, msg: msg}}
res, _ := json.Marshal(m) res, _ := json.Marshal(m)
val, _ := call.Otto.Run("(" + string(res) + ")") val, _ := otto.Run("(" + string(res) + ")")
return val return val
} }
func newResultResponse(call otto.FunctionCall, result interface{}) otto.Value { func newResultResponse(vm *otto.Otto, result interface{}) otto.Value {
resp, _ := call.Otto.Object(`({"jsonrpc":"2.0"})`) resp, _ := vm.Object(`({"jsonrpc":"2.0"})`)
resp.Set("result", result) // nolint: errcheck resp.Set("result", result) // nolint: errcheck
return resp.Value() return resp.Value()

139
geth/jail/jail_cell.go Normal file
View File

@ -0,0 +1,139 @@
package jail
import (
"sync"
"fknsrs.biz/p/ottoext/fetch"
"fknsrs.biz/p/ottoext/loop"
"fknsrs.biz/p/ottoext/timers"
"github.com/robertkrimen/otto"
)
const (
// JailCellRequestTimeout seconds before jailed request times out.
JailCellRequestTimeout = 60
)
// JailCell represents single jail cell, which is basically a JavaScript VM.
// TODO(influx6): Rename JailCell to Cell in next refactoring phase.
type JailCell struct {
sync.Mutex
id string
vm *otto.Otto
lo *loop.Loop
}
// newJailCell encapsulates what we need to create a new jailCell from the
// provided vm and eventloop instance.
func newJailCell(id string, vm *otto.Otto, lo *loop.Loop) (*JailCell, error) {
// Register fetch provider from ottoext.
if err := fetch.Define(vm, lo); err != nil {
return nil, err
}
// Register event loop for timers.
if err := timers.Define(vm, lo); err != nil {
return nil, err
}
return &JailCell{
id: id,
vm: vm,
lo: lo,
}, nil
}
// Fetch attempts to call the underline Fetch API added through the
// ottoext package.
func (cell *JailCell) Fetch(url string, callback func(otto.Value)) (otto.Value, error) {
val, err := cell.prepareFetchCall(url, callback)
if err != nil {
return val, err
}
return val, cell.lo.Run()
}
// prepareFetchCall prepares the needed calls to hook into the vm to receive the expected response
// for a call to the FetchAPI. We need this to ensure confidence in mutex locking and unlocking.
func (cell *JailCell) prepareFetchCall(url string, callback func(otto.Value)) (otto.Value, error) {
cell.Lock()
defer cell.Unlock()
if err := cell.vm.Set("__captureFetch", callback); err != nil {
return otto.UndefinedValue(), err
}
return cell.vm.Run(`fetch("` + url + `").then(function(response){
__captureFetch({
"url": response.url,
"type": response.type,
"body": response.text(),
"status": response.status,
"headers": response.headers,
});
});
`)
}
// Set sets the value to be keyed by the provided keyname.
func (cell *JailCell) Set(key string, val interface{}) error {
cell.Lock()
defer cell.Unlock()
return cell.vm.Set(key, val)
}
// Get returns the giving key's otto.Value from the underline otto vm.
func (cell *JailCell) Get(key string) (otto.Value, error) {
cell.Lock()
defer cell.Unlock()
return cell.vm.Get(key)
}
// RunOnLoop evaluates the giving js string on the associated vm loop returning
// an error.
func (cell *JailCell) RunOnLoop(val string) (otto.Value, error) {
cell.Lock()
defer cell.Unlock()
res, err := cell.vm.Run(val)
if err != nil {
return res, err
}
return res, cell.lo.Run()
}
// CallOnLoop attempts to call the internal call function for the giving response associated with the
// proper values.
func (cell *JailCell) CallOnLoop(item string, this interface{}, args ...interface{}) (otto.Value, error) {
cell.Lock()
defer cell.Unlock()
res, err := cell.vm.Call(item, this, args...)
if err != nil {
return res, err
}
return res, cell.lo.Run()
}
// Call attempts to call the internal call function for the giving response associated with the
// proper values.
func (cell *JailCell) Call(item string, this interface{}, args ...interface{}) (otto.Value, error) {
cell.Lock()
defer cell.Unlock()
return cell.vm.Call(item, this, args...)
}
// Run evaluates the giving js string on the associated vm llop.
func (cell *JailCell) Run(val string) (otto.Value, error) {
cell.Lock()
defer cell.Unlock()
return cell.vm.Run(val)
}

135
geth/jail/jail_cell_test.go Normal file
View File

@ -0,0 +1,135 @@
package jail_test
import (
"net/http"
"net/http/httptest"
"time"
"github.com/robertkrimen/otto"
"github.com/status-im/status-go/geth/jail"
"github.com/status-im/status-go/geth/params"
)
func (s *JailTestSuite) TestJailTimeoutFailure() {
require := s.Require()
require.NotNil(s.jail)
newCell, err := s.jail.NewJailCell(testChatID)
require.NoError(err)
require.NotNil(newCell)
// Attempt to run a timeout string against a JailCell.
_, err = newCell.RunOnLoop(`
setTimeout(function(n){
if(Date.now() - n < 50){
throw new Error("Timedout early");
}
return n;
}, 30, Date.now());
`)
require.NotNil(err)
}
func (s *JailTestSuite) TestJailTimeout() {
require := s.Require()
require.NotNil(s.jail)
newCell, err := s.jail.NewJailCell(testChatID)
require.NoError(err)
require.NotNil(newCell)
// Attempt to run a timeout string against a JailCell.
res, err := newCell.RunOnLoop(`
setTimeout(function(n){
if(Date.now() - n < 50){
throw new Error("Timedout early");
}
return n;
}, 50, Date.now());
`)
require.NoError(err)
require.NotNil(res)
}
func (s *JailTestSuite) TestJailFetch() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello World"))
})
server := httptest.NewServer(mux)
defer server.Close()
require := s.Require()
require.NotNil(s.jail)
newCell, err := s.jail.NewJailCell(testChatID)
require.NoError(err)
require.NotNil(newCell)
jcell, ok := newCell.(*jail.JailCell)
require.Equal(ok, true)
require.NotNil(jcell)
wait := make(chan struct{})
// Attempt to run a fetch resource.
_, err = jcell.Fetch(server.URL, func(res otto.Value) {
go func() { wait <- struct{}{} }()
})
require.NoError(err)
<-wait
}
func (s *JailTestSuite) TestJailLoopInCall() {
require := s.Require()
require.NotNil(s.jail)
s.StartTestNode(params.RopstenNetworkID)
defer s.StopTestNode()
// load Status JS and add test command to it
s.jail.BaseJS(baseStatusJSCode)
s.jail.Parse(testChatID, ``)
cell, err := s.jail.GetCell(testChatID)
require.NoError(err)
require.NotNil(cell)
items := make(chan string)
err = cell.Set("__captureResponse", func(val string) otto.Value {
go func() { items <- val }()
return otto.UndefinedValue()
})
require.NoError(err)
_, err = cell.Run(`
function callRunner(namespace){
console.log("Initiating callRunner for: ", namespace)
return setTimeout(function(){
__captureResponse(namespace);
}, 1000);
}
`)
require.NoError(err)
_, err = cell.CallOnLoop("callRunner", nil, "softball")
require.NoError(err)
select {
case received := <-items:
require.Equal(received, "softball")
break
case <-time.After(5 * time.Second):
require.Fail("Failed to received event response")
}
}

View File

@ -3,12 +3,9 @@ package jail_test
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"net/http"
"net/http/httptest"
"testing" "testing"
"time" "time"
"github.com/robertkrimen/otto"
"github.com/status-im/status-go/geth/jail" "github.com/status-im/status-go/geth/jail"
"github.com/status-im/status-go/geth/node" "github.com/status-im/status-go/geth/node"
"github.com/status-im/status-go/geth/params" "github.com/status-im/status-go/geth/params"
@ -50,9 +47,9 @@ func (s *JailTestSuite) TestInit() {
} }
// get cell VM w/o defining cell first // get cell VM w/o defining cell first
vm, err := s.jail.JailCellVM(testChatID) cell, err := s.jail.GetCell(testChatID)
require.EqualError(err, "cell[testChat] doesn't exist") require.EqualError(err, "cell[testChat] doesn't exist")
require.Nil(vm) require.Nil(cell)
// create VM (w/o properly initializing base JS script) // create VM (w/o properly initializing base JS script)
err = errors.New("ReferenceError: '_status_catalog' is not defined") err = errors.New("ReferenceError: '_status_catalog' is not defined")
@ -61,9 +58,9 @@ func (s *JailTestSuite) TestInit() {
require.Equal(errorWrapper(err), s.jail.Call(testChatID, `["commands", "testCommand"]`, `{"val": 12}`)) require.Equal(errorWrapper(err), s.jail.Call(testChatID, `["commands", "testCommand"]`, `{"val": 12}`))
// get existing cell (even though we got errors, cell was still created) // get existing cell (even though we got errors, cell was still created)
vm, err = s.jail.JailCellVM(testChatID) cell, err = s.jail.GetCell(testChatID)
require.NoError(err) require.NoError(err)
require.NotNil(vm) require.NotNil(cell)
statusJS := baseStatusJSCode + `; statusJS := baseStatusJSCode + `;
_status_catalog.commands["testCommand"] = function (params) { _status_catalog.commands["testCommand"] = function (params) {
@ -109,7 +106,7 @@ func (s *JailTestSuite) TestFunctionCall() {
// call with wrong chat id // call with wrong chat id
response := s.jail.Call("chatIDNonExistent", "", "") response := s.jail.Call("chatIDNonExistent", "", "")
expectedError := `{"error":"Cell[chatIDNonExistent] doesn't exist."}` expectedError := `{"error":"cell[chatIDNonExistent] doesn't exist"}`
require.Equal(expectedError, response) require.Equal(expectedError, response)
// call extraFunc() // call extraFunc()
@ -118,83 +115,6 @@ func (s *JailTestSuite) TestFunctionCall() {
require.Equal(expectedResponse, response) require.Equal(expectedResponse, response)
} }
func (s *JailTestSuite) TestJailTimeoutFailure() {
require := s.Require()
require.NotNil(s.jail)
newCell := s.jail.NewJailCell(testChatID)
require.NotNil(newCell)
execr := newCell.Executor()
// Attempt to run a timeout string against a JailCell.
_, err := execr.Exec(`
setTimeout(function(n){
if(Date.now() - n < 50){
throw new Error("Timedout early");
}
return n;
}, 30, Date.now());
`)
require.NotNil(err)
}
func (s *JailTestSuite) TestJailTimeout() {
require := s.Require()
require.NotNil(s.jail)
newCell := s.jail.NewJailCell(testChatID)
require.NotNil(newCell)
execr := newCell.Executor()
// Attempt to run a timeout string against a JailCell.
res, err := execr.Exec(`
setTimeout(function(n){
if(Date.now() - n < 50){
throw new Error("Timedout early");
}
return n;
}, 50, Date.now());
`)
require.NoError(err)
require.NotNil(res)
}
func (s *JailTestSuite) TestJailFetch() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello World"))
})
server := httptest.NewServer(mux)
defer server.Close()
require := s.Require()
require.NotNil(s.jail)
newCell := s.jail.NewJailCell(testChatID)
require.NotNil(newCell)
execr := newCell.Executor()
wait := make(chan struct{})
// Attempt to run a fetch resource.
_, err := execr.Fetch(server.URL, func(res otto.Value) {
go func() { wait <- struct{}{} }()
})
require.NoError(err)
<-wait
}
func (s *JailTestSuite) TestJailRPCSend() { func (s *JailTestSuite) TestJailRPCSend() {
require := s.Require() require := s.Require()
require.NotNil(s.jail) require.NotNil(s.jail)
@ -207,19 +127,19 @@ func (s *JailTestSuite) TestJailRPCSend() {
s.jail.Parse(testChatID, ``) s.jail.Parse(testChatID, ``)
// obtain VM for a given chat (to send custom JS to jailed version of Send()) // obtain VM for a given chat (to send custom JS to jailed version of Send())
vm, err := s.jail.JailCellVM(testChatID) cell, err := s.jail.GetCell(testChatID)
require.NoError(err) require.NoError(err)
require.NotNil(vm) require.NotNil(cell)
// internally (since we replaced `web3.send` with `jail.Send`) // internally (since we replaced `web3.send` with `jail.Send`)
// all requests to web3 are forwarded to `jail.Send` // all requests to web3 are forwarded to `jail.Send`
_, err = vm.Run(` _, err = cell.Run(`
var balance = web3.eth.getBalance("` + TestConfig.Account1.Address + `"); var balance = web3.eth.getBalance("` + TestConfig.Account1.Address + `");
var sendResult = web3.fromWei(balance, "ether") var sendResult = web3.fromWei(balance, "ether")
`) `)
require.NoError(err) require.NoError(err)
value, err := vm.Get("sendResult") value, err := cell.Get("sendResult")
require.NoError(err, "cannot obtain result of balance check operation") require.NoError(err, "cannot obtain result of balance check operation")
balance, err := value.ToFloat() balance, err := value.ToFloat()
@ -229,39 +149,27 @@ func (s *JailTestSuite) TestJailRPCSend() {
require.False(balance < 100, "wrong balance (there should be lots of test Ether on that account)") require.False(balance < 100, "wrong balance (there should be lots of test Ether on that account)")
} }
func (s *JailTestSuite) TestGetJailCellVM() {
expectedError := `cell[nonExistentChat] doesn't exist`
_, err := s.jail.JailCellVM("nonExistentChat")
s.EqualError(err, expectedError)
// now let's create VM..
s.jail.Parse(testChatID, ``)
// ..and see if VM becomes available
_, err = s.jail.JailCellVM(testChatID)
s.NoError(err)
}
func (s *JailTestSuite) TestIsConnected() { func (s *JailTestSuite) TestIsConnected() {
require := s.Require() require := s.Require()
require.NotNil(s.jail) require.NotNil(s.jail)
// TODO(tiabc): Is this required?
s.StartTestNode(params.RopstenNetworkID) s.StartTestNode(params.RopstenNetworkID)
defer s.StopTestNode() defer s.StopTestNode()
s.jail.Parse(testChatID, "") s.jail.Parse(testChatID, "")
// obtain VM for a given chat (to send custom JS to jailed version of Send()) // obtain VM for a given chat (to send custom JS to jailed version of Send())
vm, err := s.jail.JailCellVM(testChatID) cell, err := s.jail.GetCell(testChatID)
require.NoError(err) require.NoError(err)
_, err = vm.Run(` _, err = cell.Run(`
var responseValue = web3.isConnected(); var responseValue = web3.isConnected();
responseValue = JSON.stringify(responseValue); responseValue = JSON.stringify(responseValue);
`) `)
require.NoError(err) require.NoError(err)
responseValue, err := vm.Get("responseValue") responseValue, err := cell.Get("responseValue")
require.NoError(err, "cannot obtain result of isConnected()") require.NoError(err, "cannot obtain result of isConnected()")
response, err := responseValue.ToString() response, err := responseValue.ToString()
@ -278,7 +186,7 @@ func (s *JailTestSuite) TestLocalStorageSet() {
s.jail.Parse(testChatID, "") s.jail.Parse(testChatID, "")
// obtain VM for a given chat (to send custom JS to jailed version of Send()) // obtain VM for a given chat (to send custom JS to jailed version of Send())
vm, err := s.jail.JailCellVM(testChatID) cell, err := s.jail.GetCell(testChatID)
require.NoError(err) require.NoError(err)
testData := "foobar" testData := "foobar"
@ -306,7 +214,7 @@ func (s *JailTestSuite) TestLocalStorageSet() {
} }
}) })
_, err = vm.Run(` _, err = cell.Run(`
var responseValue = localStorage.set("` + testData + `"); var responseValue = localStorage.set("` + testData + `");
responseValue = JSON.stringify(responseValue); responseValue = JSON.stringify(responseValue);
`) `)
@ -320,7 +228,7 @@ func (s *JailTestSuite) TestLocalStorageSet() {
s.Fail("operation timed out") s.Fail("operation timed out")
} }
responseValue, err := vm.Get("responseValue") responseValue, err := cell.Get("responseValue")
s.NoError(err, "cannot obtain result of localStorage.set()") s.NoError(err, "cannot obtain result of localStorage.set()")
response, err := responseValue.ToString() response, err := responseValue.ToString()

View File

@ -23,6 +23,7 @@ type RequestManager struct {
nodeManager common.NodeManager nodeManager common.NodeManager
} }
// NewRequestManager returns a new instance of the RequestManager pointer.
func NewRequestManager(nodeManager common.NodeManager) *RequestManager { func NewRequestManager(nodeManager common.NodeManager) *RequestManager {
return &RequestManager{ return &RequestManager{
nodeManager: nodeManager, nodeManager: nodeManager,
@ -38,6 +39,7 @@ func (m *RequestManager) PreProcessRequest(vm *otto.Otto, req RPCCall) (string,
// PostProcessRequest post-processes a given RPC call to a given Otto VM // PostProcessRequest post-processes a given RPC call to a given Otto VM
func (m *RequestManager) PostProcessRequest(vm *otto.Otto, req RPCCall, messageID string) { func (m *RequestManager) PostProcessRequest(vm *otto.Otto, req RPCCall, messageID string) {
// Errors are ignored because addContext may not exist and it's alright.
if len(messageID) > 0 { if len(messageID) > 0 {
vm.Call("addContext", nil, messageID, common.MessageIDKey, messageID) // nolint: errcheck vm.Call("addContext", nil, messageID, common.MessageIDKey, messageID) // nolint: errcheck
} }

View File

@ -241,11 +241,7 @@ func (m *NodeManager) populateStaticPeers() error {
return nil return nil
} }
enodes, err := m.config.LoadBootClusterNodes() for _, enode := range m.config.BootClusterConfig.BootNodes {
if err != nil {
log.Warn("Can not load boot nodes", "error", err)
}
for _, enode := range enodes {
err := m.addPeer(enode) err := m.addPeer(enode)
if err != nil { if err != nil {
log.Warn("Boot node addition failed", "error", err) log.Warn("Boot node addition failed", "error", err)

View File

@ -4,13 +4,10 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"time"
gethcommon "github.com/ethereum/go-ethereum/common" gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
@ -74,17 +71,6 @@ func MakeNode(config *params.NodeConfig) (*node.Node, error) {
stackConfig.P2P.PrivateKey = pk stackConfig.P2P.PrivateKey = pk
} }
if len(config.NodeKeyFile) > 0 {
log.Info("Loading private key file", "file", config.NodeKeyFile)
pk, err := crypto.LoadECDSA(config.NodeKeyFile)
if err != nil {
log.Info("Failed loading private key file", "file", config.NodeKeyFile, "err", err)
}
// override node's private key
stackConfig.P2P.PrivateKey = pk
}
stack, err := node.New(stackConfig) stack, err := node.New(stackConfig)
if err != nil { if err != nil {
return nil, ErrNodeMakeFailure return nil, ErrNodeMakeFailure
@ -142,90 +128,24 @@ func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config {
// updateCHT changes trusted canonical hash trie root // updateCHT changes trusted canonical hash trie root
func updateCHT(eth *les.LightEthereum, config *params.NodeConfig) { func updateCHT(eth *les.LightEthereum, config *params.NodeConfig) {
bc := eth.BlockChain() if !config.BootClusterConfig.Enabled {
return
// TODO: Remove this thing as this is an ugly hack.
// Once CHT sync sub-protocol is working in LES, we will rely on it, as it provides
// decentralized solution. For now, in order to avoid forcing users to long sync times
// we use central static resource
type MsgCHTRoot struct {
GenesisHash string `json:"net"`
Number uint64 `json:"number"`
Prod string `json:"prod"`
Dev string `json:"dev"`
}
loadCHTLists := func() ([]MsgCHTRoot, error) {
url := config.LightEthConfig.CHTRootConfigURL + "?u=" + strconv.Itoa(int(time.Now().Unix()))
client := &http.Client{Timeout: 5 * time.Second}
r, err := client.Get(url)
if err != nil {
return nil, err
}
defer r.Body.Close()
var roots []MsgCHTRoot
err = json.NewDecoder(r.Body).Decode(&roots)
if err != nil {
return nil, err
}
return roots, nil
}
if roots, err := loadCHTLists(); err == nil {
for _, root := range roots {
if bc.Genesis().Hash().Hex() == root.GenesisHash {
log.Info("Loaded root", "root", root)
if root.Number == 0 {
continue
}
chtRoot := root.Prod
if config.DevMode {
chtRoot = root.Dev
}
eth.WriteTrustedCht(light.TrustedCht{
Number: root.Number,
Root: gethcommon.HexToHash(chtRoot),
})
log.Info("Loaded CHT from net", "CHT", chtRoot, "number", root.Number, "dev", config.DevMode)
return
}
}
} }
// resort to manually updated if config.BootClusterConfig.RootNumber == 0 {
log.Info("Loading CHT from net failed, setting manually") return
if bc.Genesis().Hash() == params.MainNetGenesisHash {
eth.WriteTrustedCht(light.TrustedCht{
Number: 805,
Root: gethcommon.HexToHash("85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f"),
})
log.Info("Added trusted CHT for mainnet")
} }
if bc.Genesis().Hash() == params.RopstenNetGenesisHash { if config.BootClusterConfig.RootHash == "" {
root := "fa851b5252cc48ab55f375833b0344cc5c7cacea69be7e2a57976c38d3bb3aef" return
if config.DevMode {
root = "f2f862314509b22a773eedaaa7fa6452474eb71a3b72525a97dbf5060cbea88f"
}
eth.WriteTrustedCht(light.TrustedCht{
Number: 239,
Root: gethcommon.HexToHash(root),
})
log.Info("Added trusted CHT for Ropsten", "CHT", root)
} }
//if bc.Genesis().Hash() == params.RinkebyNetGenesisHash { eth.WriteTrustedCht(light.TrustedCht{
// root := "0xb100882d00a09292f15e712707649b24d019a47a509e83a00530ac542425c3bd" Number: uint64(config.BootClusterConfig.RootNumber),
// if config.DevMode { Root: gethcommon.HexToHash(config.BootClusterConfig.RootHash),
// root = "0xb100882d00a09292f15e712707649b24d019a47a509e83a00530ac542425c3bd" })
// } log.Info("Added trusted CHT",
// eth.WriteTrustedCht(light.TrustedCht{ "develop", config.DevMode, "number", config.BootClusterConfig.RootNumber, "hash", config.BootClusterConfig.RootHash)
// Number: 55,
// Root: gethcommon.HexToHash(root),
// })
// log.Info("Added trusted CHT for Rinkeby", "CHT", root)
//}
} }
// activateEthService configures and registers the eth.Ethereum service with a given node. // activateEthService configures and registers the eth.Ethereum service with a given node.
@ -271,7 +191,7 @@ func activateShhService(stack *node.Node, config *params.NodeConfig) error {
serviceConstructor := func(*node.ServiceContext) (node.Service, error) { serviceConstructor := func(*node.ServiceContext) (node.Service, error) {
whisperConfig := config.WhisperConfig whisperConfig := config.WhisperConfig
whisperService := whisper.New() whisperService := whisper.New(nil)
// enable mail service // enable mail service
if whisperConfig.MailServerNode { if whisperConfig.MailServerNode {

View File

@ -7,14 +7,16 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"time"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/static"
) )
// default node configuration options // default node configuration options
@ -52,14 +54,8 @@ type LightEthConfig struct {
// DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced) // DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
DatabaseCache int DatabaseCache int
// CHTRootConfigURL defines URL to file containing hard-coded CHT roots
// TODO remove this hack, once CHT sync is implemented on LES side
CHTRootConfigURL string
} }
//=====================================================================================
// FirebaseConfig holds FCM-related configuration // FirebaseConfig holds FCM-related configuration
type FirebaseConfig struct { type FirebaseConfig struct {
// AuthorizationKeyFile file path that contains FCM authorization key // AuthorizationKeyFile file path that contains FCM authorization key
@ -89,8 +85,6 @@ func (c *FirebaseConfig) ReadAuthorizationKeyFile() ([]byte, error) {
return key, nil return key, nil
} }
//=====================================================================================
// WhisperConfig holds SHH-related configuration // WhisperConfig holds SHH-related configuration
type WhisperConfig struct { type WhisperConfig struct {
// Enabled flag specifies whether protocol is enabled // Enabled flag specifies whether protocol is enabled
@ -177,8 +171,6 @@ func (c *WhisperConfig) String() string {
return string(data) return string(data)
} }
//=====================================================================================
// SwarmConfig holds Swarm-related configuration // SwarmConfig holds Swarm-related configuration
type SwarmConfig struct { type SwarmConfig struct {
// Enabled flag specifies whether protocol is enabled // Enabled flag specifies whether protocol is enabled
@ -191,8 +183,6 @@ func (c *SwarmConfig) String() string {
return string(data) return string(data)
} }
//=====================================================================================
// BootClusterConfig holds configuration for supporting boot cluster, which is a temporary // BootClusterConfig holds configuration for supporting boot cluster, which is a temporary
// means for mobile devices to get connected to Ethereum network (UDP-based discovery // means for mobile devices to get connected to Ethereum network (UDP-based discovery
// may not be available, so we need means to discover the network manually). // may not be available, so we need means to discover the network manually).
@ -200,12 +190,15 @@ type BootClusterConfig struct {
// Enabled flag specifies whether feature is enabled // Enabled flag specifies whether feature is enabled
Enabled bool Enabled bool
// ConfigFile is a path to JSON file containing array of boot nodes // RootNumber CHT root number
// See `static/bootcluster/*.json` for cluster configurations provided RootNumber int
// out of box. You can pass absolute path, and if file at that path can be
// loaded, it will be used. Otherwise, file is supposed to be relative to // RootHash is hash of CHT root for a given root number
// `static/bootcluster` folder. RootHash string
ConfigFile string
// BootNodes list of bootstrap nodes for a given network (Ropsten, Rinkeby, Homestead),
// for a given mode (production vs development)
BootNodes []string
} }
// String dumps config object as nicely indented JSON // String dumps config object as nicely indented JSON
@ -214,8 +207,6 @@ func (c *BootClusterConfig) String() string {
return string(data) return string(data)
} }
//=====================================================================================
// NodeConfig stores configuration options for a node // NodeConfig stores configuration options for a node
type NodeConfig struct { type NodeConfig struct {
// DevMode is true when given configuration is to be used during development. // DevMode is true when given configuration is to be used during development.
@ -320,6 +311,7 @@ func NewNodeConfig(dataDir string, networkID uint64, devMode bool) (*NodeConfig,
RPCEnabled: RPCEnabledDefault, RPCEnabled: RPCEnabledDefault,
HTTPHost: HTTPHost, HTTPHost: HTTPHost,
HTTPPort: HTTPPort, HTTPPort: HTTPPort,
APIModules: APIModules,
WSHost: WSHost, WSHost: WSHost,
WSPort: WSPort, WSPort: WSPort,
MaxPeers: MaxPeers, MaxPeers: MaxPeers,
@ -328,14 +320,13 @@ func NewNodeConfig(dataDir string, networkID uint64, devMode bool) (*NodeConfig,
LogFile: LogFile, LogFile: LogFile,
LogLevel: LogLevel, LogLevel: LogLevel,
LogToStderr: LogToStderr, LogToStderr: LogToStderr,
LightEthConfig: &LightEthConfig{
Enabled: true,
DatabaseCache: DatabaseCache,
CHTRootConfigURL: CHTRootConfigURL,
},
BootClusterConfig: &BootClusterConfig{ BootClusterConfig: &BootClusterConfig{
Enabled: true, Enabled: true,
ConfigFile: BootClusterConfigFile, BootNodes: []string{},
},
LightEthConfig: &LightEthConfig{
Enabled: true,
DatabaseCache: DatabaseCache,
}, },
WhisperConfig: &WhisperConfig{ WhisperConfig: &WhisperConfig{
Enabled: true, Enabled: true,
@ -408,41 +399,12 @@ func (c *NodeConfig) Save() error {
return nil return nil
} }
// LoadBootClusterNodes loads boot nodes from a config file provided in BootClusterConfig
func (c *NodeConfig) LoadBootClusterNodes() ([]string, error) {
var bootnodes []string
var configData []byte
var err error
filename := c.BootClusterConfig.ConfigFile
log.Info("Loading boot nodes config file", "source", filename)
if _, err = os.Stat(filename); os.IsNotExist(err) { // load from static resources
configData, err = static.Asset("bootcluster/" + filename)
} else {
configData, err = ioutil.ReadFile(filename)
}
if err != nil {
return nil, err
}
// parse JSON
if err := json.Unmarshal(configData, &bootnodes); err != nil {
return nil, err
}
return bootnodes, nil
}
// updateConfig traverses configuration and adjusts dependent fields // updateConfig traverses configuration and adjusts dependent fields
// (we have a development/production and mobile/full node dependent configurations) // (we have a development/production and mobile/full node dependent configurations)
func (c *NodeConfig) updateConfig() error { func (c *NodeConfig) updateConfig() error {
if err := c.updateGenesisConfig(); err != nil { if err := c.updateGenesisConfig(); err != nil {
return err return err
} }
if err := c.updateRPCConfig(); err != nil {
return err
}
if err := c.updateBootClusterConfig(); err != nil { if err := c.updateBootClusterConfig(); err != nil {
return err return err
} }
@ -478,36 +440,55 @@ func (c *NodeConfig) updateGenesisConfig() error {
return nil return nil
} }
// updateBootClusterConfig populates cluster config file, depending on dev/prod and mobile/full settings // updateBootClusterConfig loads boot nodes and CHT for a given network and mode.
// This is necessary until we have LES protocol support CHT sync, and better node
// discovery on mobile devices)
func (c *NodeConfig) updateBootClusterConfig() error { func (c *NodeConfig) updateBootClusterConfig() error {
var configFile string if !c.BootClusterConfig.Enabled {
return nil
switch c.NetworkID {
case MainNetworkID:
configFile = "homestead.prod.json"
case RopstenNetworkID:
configFile = "ropsten.prod.json"
case RinkebyNetworkID:
configFile = "rinkeby.prod.json"
} }
if c.DevMode { // TODO: Remove this thing as this is an ugly hack.
configFile = strings.Replace(configFile, "prod", "dev", 1) // Once CHT sync sub-protocol is working in LES, we will rely on it, as it provides
// decentralized solution. For now, in order to avoid forcing users to long sync times
// we use central static resource
type subClusterConfig struct {
Number int `json:"number"`
Hash string `json:"hash"`
BootNodes []string `json:"bootnodes"`
}
type clusterConfig struct {
NetworkID int `json:"networkID"`
GenesisHash string `json:"genesisHash"`
Prod subClusterConfig `json:"prod"`
Dev subClusterConfig `json:"dev"`
} }
if len(configFile) > 0 { client := &http.Client{Timeout: 5 * time.Second}
c.BootClusterConfig.ConfigFile = configFile r, err := client.Get(BootClusterConfigURL + "?u=" + strconv.Itoa(int(time.Now().Unix())))
if err != nil {
return err
}
defer r.Body.Close()
var clusters []clusterConfig
err = json.NewDecoder(r.Body).Decode(&clusters)
if err != nil {
return err
} }
return nil for _, cluster := range clusters {
} if cluster.NetworkID == int(c.NetworkID) {
c.BootClusterConfig.RootNumber = cluster.Prod.Number
// updateRPCConfig transforms RPC settings to meet requirements of a given configuration c.BootClusterConfig.RootHash = cluster.Prod.Hash
func (c *NodeConfig) updateRPCConfig() error { c.BootClusterConfig.BootNodes = cluster.Prod.BootNodes
c.APIModules = ProdAPIModules if c.DevMode {
c.BootClusterConfig.RootNumber = cluster.Dev.Number
if c.DevMode { c.BootClusterConfig.RootHash = cluster.Dev.Hash
c.APIModules = DevAPIModules c.BootClusterConfig.BootNodes = cluster.Dev.BootNodes
}
break
}
} }
return nil return nil

View File

@ -5,7 +5,6 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"strings" "strings"
"testing" "testing"
@ -13,6 +12,7 @@ import (
gethparams "github.com/ethereum/go-ethereum/params" gethparams "github.com/ethereum/go-ethereum/params"
"github.com/status-im/status-go/geth/params" "github.com/status-im/status-go/geth/params"
. "github.com/status-im/status-go/geth/testing" . "github.com/status-im/status-go/geth/testing"
"github.com/stretchr/testify/require"
) )
var loadConfigTestCases = []struct { var loadConfigTestCases = []struct {
@ -35,9 +35,7 @@ var loadConfigTestCases = []struct {
} }
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err == nil { require.Error(t, err, "error is expected, not thrown")
t.Fatal("error is expected, not thrown")
}
}, },
}, },
{ {
@ -47,9 +45,7 @@ var loadConfigTestCases = []struct {
"Name": "TestStatusNode" "Name": "TestStatusNode"
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != params.ErrMissingDataDir { require.Equal(t, params.ErrMissingDataDir, err)
t.Fatalf("expected error not thrown, expected: %v, thrown: %v", params.ErrMissingDataDir, err)
}
}, },
}, },
{ {
@ -58,9 +54,7 @@ var loadConfigTestCases = []struct {
"DataDir": "$TMPDIR" "DataDir": "$TMPDIR"
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != params.ErrMissingNetworkID { require.Equal(t, params.ErrMissingNetworkID, err)
t.Fatalf("expected error not thrown, expected: %v, thrown: %v", params.ErrMissingNetworkID, err)
}
}, },
}, },
{ {
@ -70,13 +64,8 @@ var loadConfigTestCases = []struct {
"DataDir": "/storage/emulated/0/ethereum/" "DataDir": "/storage/emulated/0/ethereum/"
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.Equal(t, "/storage/emulated/0/ethereum/", nodeConfig.DataDir)
}
expectedDataDir := "/storage/emulated/0/ethereum/"
if nodeConfig.DataDir != expectedDataDir {
t.Fatalf("incorrect DataDir used, expected: %v, got: %v", expectedDataDir, nodeConfig.DataDir)
}
}, },
}, },
{ {
@ -86,22 +75,13 @@ var loadConfigTestCases = []struct {
"DataDir": "$TMPDIR" "DataDir": "$TMPDIR"
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err)
}
if _, err := os.Stat(dataDir); os.IsNotExist(err) {
t.Fatalf("data directory doesn't exist: %s", dataDir)
}
expectedDataDir := dataDir _, err = os.Stat(dataDir)
if nodeConfig.DataDir != expectedDataDir { require.False(t, os.IsNotExist(err), "data directory doesn't exist")
t.Fatalf("incorrect DataDir used, expected: %v, got: %v", expectedDataDir, nodeConfig.DataDir) require.Equal(t, dataDir, nodeConfig.DataDir)
}
expectedKeyStoreDir := filepath.Join(dataDir, params.KeyStoreDir) require.Equal(t, filepath.Join(dataDir, params.KeyStoreDir), filepath.Join(dataDir, params.KeyStoreDir))
if nodeConfig.KeyStoreDir != expectedKeyStoreDir {
t.Fatalf("incorrect KeyStoreDir used, expected: %v, got: %v", expectedKeyStoreDir, nodeConfig.KeyStoreDir)
}
}, },
}, },
{ {
@ -112,18 +92,9 @@ var loadConfigTestCases = []struct {
"KeyStoreDir": "/foo/bar" "KeyStoreDir": "/foo/bar"
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.Equal(t, dataDir, nodeConfig.DataDir)
} require.Equal(t, "/foo/bar", nodeConfig.KeyStoreDir)
expectedDataDir := dataDir
if nodeConfig.DataDir != expectedDataDir {
t.Fatalf("incorrect DataDir used, expected: %v, got: %v", expectedDataDir, nodeConfig.DataDir)
}
expectedKeyStoreDir := "/foo/bar"
if nodeConfig.KeyStoreDir != expectedKeyStoreDir {
t.Fatalf("incorrect KeyStoreDir used, expected: %v, got: %v", expectedKeyStoreDir, nodeConfig.KeyStoreDir)
}
}, },
}, },
{ {
@ -141,44 +112,17 @@ var loadConfigTestCases = []struct {
} }
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err)
}
if nodeConfig.NetworkID != 3 { require.EqualValues(t, 3, nodeConfig.NetworkID)
t.Fatal("wrong NetworkId") require.Equal(t, "TestStatusNode", nodeConfig.Name)
} require.Equal(t, params.HTTPPort, nodeConfig.HTTPPort)
require.Equal(t, params.HTTPHost, nodeConfig.HTTPHost)
if nodeConfig.Name != "TestStatusNode" { require.True(t, nodeConfig.RPCEnabled)
t.Fatal("wrong Name") require.False(t, nodeConfig.WSEnabled)
} require.Equal(t, 4242, nodeConfig.WSPort)
require.True(t, nodeConfig.IPCEnabled)
if nodeConfig.HTTPPort != params.HTTPPort { require.Equal(t, 64, nodeConfig.LightEthConfig.DatabaseCache)
t.Fatal("wrong HTTPPort")
}
if nodeConfig.HTTPHost != params.HTTPHost {
t.Fatal("wrong HTTPHost")
}
if !nodeConfig.RPCEnabled {
t.Fatal("Wrong RPCEnabled flag")
}
if nodeConfig.WSPort != 4242 {
t.Fatal("wrong WSPort")
}
if nodeConfig.WSEnabled {
t.Fatal("wrong WSEnabled")
}
if !nodeConfig.IPCEnabled {
t.Fatal("wrong IPCEnabled")
}
if nodeConfig.LightEthConfig.DatabaseCache != 64 {
t.Fatal("wrong LightEthConfig.DatabaseCache")
}
}, },
}, },
{ {
@ -195,41 +139,25 @@ var loadConfigTestCases = []struct {
} }
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err)
}
genesis := new(core.Genesis) genesis := new(core.Genesis)
if err := json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis); err != nil { err = json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis)
t.Fatal(err) require.NoError(t, err)
}
chainConfig := genesis.Config chainConfig := genesis.Config
refChainConfig := gethparams.TestnetChainConfig refChainConfig := gethparams.TestnetChainConfig
if chainConfig.HomesteadBlock.Cmp(refChainConfig.HomesteadBlock) != 0 { require.Empty(t, chainConfig.HomesteadBlock.Cmp(refChainConfig.HomesteadBlock), "invalid chainConfig.HomesteadBlock")
t.Fatal("invalid chainConfig.HomesteadBlock") require.Nil(t, chainConfig.DAOForkBlock)
} require.Equal(t, refChainConfig.DAOForkSupport, chainConfig.DAOForkSupport)
if chainConfig.DAOForkBlock != nil { // already forked
t.Fatal("invalid chainConfig.DAOForkBlock") require.Empty(t, chainConfig.EIP150Block.Cmp(refChainConfig.EIP150Block))
} require.Equal(t, refChainConfig.EIP150Hash, chainConfig.EIP150Hash)
if chainConfig.DAOForkSupport != refChainConfig.DAOForkSupport {
t.Fatal("invalid chainConfig.DAOForkSupport") require.Empty(t, chainConfig.EIP155Block.Cmp(refChainConfig.EIP155Block))
} require.Empty(t, chainConfig.EIP158Block.Cmp(refChainConfig.EIP158Block))
if chainConfig.EIP150Block.Cmp(refChainConfig.EIP150Block) != 0 { require.Empty(t, chainConfig.ChainId.Cmp(refChainConfig.ChainId))
t.Fatal("invalid chainConfig.EIP150Block")
}
if chainConfig.EIP150Hash != refChainConfig.EIP150Hash {
t.Fatal("invalid chainConfig.EIP150Hash")
}
if chainConfig.EIP155Block.Cmp(refChainConfig.EIP155Block) != 0 {
t.Fatal("invalid chainConfig.EIP155Block")
}
if chainConfig.EIP158Block.Cmp(refChainConfig.EIP158Block) != 0 {
t.Fatal("invalid chainConfig.EIP158Block")
}
if chainConfig.ChainId.Cmp(refChainConfig.ChainId) != 0 {
t.Fatal("invalid chainConfig.ChainId")
}
}, },
}, },
{ {
@ -246,39 +174,22 @@ var loadConfigTestCases = []struct {
} }
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err)
}
genesis := new(core.Genesis) genesis := new(core.Genesis)
if err := json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis); err != nil { err = json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis)
t.Fatal(err) require.NoError(t, err)
}
chainConfig := genesis.Config chainConfig := genesis.Config
if chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock) != 0 {
t.Fatal("invalid chainConfig.HomesteadBlock") require.Empty(t, chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock))
} require.Empty(t, chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock))
if chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock) != 0 { require.True(t, chainConfig.DAOForkSupport)
t.Fatal("invalid chainConfig.DAOForkBlock") require.Empty(t, chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock))
} require.Equal(t, gethparams.MainNetHomesteadGasRepriceHash, chainConfig.EIP150Hash)
if !chainConfig.DAOForkSupport { require.Empty(t, chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon))
t.Fatal("invalid chainConfig.DAOForkSupport") require.Empty(t, chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon))
} require.Empty(t, chainConfig.ChainId.Cmp(gethparams.MainNetChainID))
if chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock) != 0 {
t.Fatal("invalid chainConfig.EIP150Block")
}
if chainConfig.EIP150Hash != gethparams.MainNetHomesteadGasRepriceHash {
t.Fatal("invalid chainConfig.EIP150Hash")
}
if chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
t.Fatal("invalid chainConfig.EIP155Block")
}
if chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
t.Fatal("invalid chainConfig.EIP158Block")
}
if chainConfig.ChainId.Cmp(gethparams.MainNetChainID) != 0 {
t.Fatal("invalid chainConfig.ChainId")
}
}, },
}, },
{ {
@ -292,14 +203,8 @@ var loadConfigTestCases = []struct {
"WSEnabled": false "WSEnabled": false
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.EqualValues(t, 311, nodeConfig.NetworkID)
}
networkId := uint64(311)
if nodeConfig.NetworkID != networkId {
t.Fatalf("unexpected NetworkID, expected: %v, got: %v", networkId, nodeConfig.NetworkID)
}
}, },
}, },
{ {
@ -309,36 +214,32 @@ var loadConfigTestCases = []struct {
"DataDir": "$TMPDIR" "DataDir": "$TMPDIR"
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { // Bootnodes for dev and prod modes are the same so no need for a separate Ropsten Prod test.
t.Fatalf("unexpected error: %v", err)
}
if nodeConfig.BootClusterConfig.ConfigFile != params.BootClusterConfigFile { require.NoError(t, err)
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v", require.True(t, nodeConfig.BootClusterConfig.Enabled, "boot cluster is expected to be enabled by default")
params.BootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile) require.Equal(t, "91825fffecb5678167273955deaddbf03c26ae04287cfda61403c0bad5ceab8d", nodeConfig.BootClusterConfig.RootHash)
} require.Equal(t, 259, nodeConfig.BootClusterConfig.RootNumber)
if !nodeConfig.BootClusterConfig.Enabled { enodes := nodeConfig.BootClusterConfig.BootNodes
t.Fatal("boot cluster is expected to be enabled by default")
}
enodes, err := nodeConfig.LoadBootClusterNodes()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedEnodes := []string{ expectedEnodes := []string{
"enode://da3bf389a031f33fb55c9f5f54fde8473912402d27fffaa50efd74c0d0515f3a61daf6d52151f2876b19c15828e6f670352bff432b5ec457652e74755e8c864f@51.15.62.116:30303", "enode://7ab298cedc4185a894d21d8a4615262ec6bdce66c9b6783878258e0d5b31013d30c9038932432f70e5b2b6a5cd323bf820554fcb22fbc7b45367889522e9c449@51.15.63.93:30303",
"enode://584c0db89b00719e9e7b1b5c32a4a8942f379f4d5d66bb69f9c7fa97fa42f64974e7b057b35eb5a63fd7973af063f9a1d32d8c60dbb4854c64cb8ab385470258@51.15.35.2:30303", "enode://f59e8701f18c79c5cbc7618dc7bb928d44dc2f5405c7d693dad97da2d8585975942ec6fd36d3fe608bfdc7270a34a4dd00f38cfe96b2baa24f7cd0ac28d382a1@51.15.79.88:30303",
"enode://e71ba996b923e4756783375e0ed1f29963b7f759305926315d3cf9a71364d2980dbc86b1c1549812c720b38f60d347149f1ba33681c5cd4c8fca4ee8116efec6@51.15.35.70:30303", "enode://e2a3587b7b41acfc49eddea9229281905d252efba0baf565cf6276df17faf04801b7879eead757da8b5be13b05f25e775ab6d857ff264bc53a89c027a657dd10@51.15.45.114:30303",
"enode://829f09a946bcac67afbd7b8face82c48106af6a6b2507c007de6c79b2dbdf5544368afdf93cf5218d6d75a1f0219e6312db48bcc2f0fdfacb1d82c81f061d623@51.15.54.229:30303", "enode://fe991752c4ceab8b90608fbf16d89a5f7d6d1825647d4981569ebcece1b243b2000420a5db721e214231c7a6da3543fa821185c706cbd9b9be651494ec97f56a@51.15.67.119:30303",
"enode://e80276aabb7682a4a659f4341c1199de79d91a2e500a6ee9bed16ed4ce927ba8d32ba5dea357739ffdf2c5bcc848d3064bb6f149f0b4249c1f7e53f8bf02bfc8@51.15.39.57:30303", "enode://482484b9198530ee2e00db89791823244ca41dcd372242e2e1297dd06f6d8dd357603960c5ad9cc8dc15fcdf0e4edd06b7ad7db590e67a0b54f798c26581ebd7@51.15.75.138:30303",
} "enode://9e99e183b5c71d51deb16e6b42ac9c26c75cfc95fff9dfae828b871b348354cbecf196dff4dd43567b26c8241b2b979cb4ea9f8dae2d9aacf86649dafe19a39a@51.15.79.176:30303",
if len(enodes) != len(expectedEnodes) { "enode://12d52c3796700fb5acff2c7d96df7bbb6d7109b67f3442ee3d99ac1c197016cddb4c3568bbeba05d39145c59c990cd64f76bc9b00d4b13f10095c49507dd4cf9@51.15.63.110:30303",
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes)) "enode://0f7c65277f916ff4379fe520b875082a56e587eb3ce1c1567d9ff94206bdb05ba167c52272f20f634cd1ebdec5d9dfeb393018bfde1595d8e64a717c8b46692f@51.15.54.150:30303",
} "enode://e006f0b2dc98e757468b67173295519e9b6d5ff4842772acb18fd055c620727ab23766c95b8ee1008dea9e8ef61e83b1515ddb3fb56dbfb9dbf1f463552a7c9f@212.47.237.127:30303",
if !reflect.DeepEqual(enodes, expectedEnodes) { "enode://d40871fc3e11b2649700978e06acd68a24af54e603d4333faecb70926ca7df93baa0b7bf4e927fcad9a7c1c07f9b325b22f6d1730e728314d0e4e6523e5cebc2@51.15.132.235:30303",
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes) "enode://ea37c9724762be7f668e15d3dc955562529ab4f01bd7951f0b3c1960b75ecba45e8c3bb3c8ebe6a7504d9a40dd99a562b13629cc8e5e12153451765f9a12a61d@163.172.189.205:30303",
"enode://88c2b24429a6f7683fbfd06874ae3f1e7c8b4a5ffb846e77c705ba02e2543789d66fc032b6606a8d8888eb6239a2abe5897ce83f78dcdcfcb027d6ea69aa6fe9@163.172.157.61:30303",
"enode://ce6854c2c77a8800fcc12600206c344b8053bb90ee3ba280e6c4f18f3141cdc5ee80bcc3bdb24cbc0e96dffd4b38d7b57546ed528c00af6cd604ab65c4d528f6@163.172.153.124:30303",
"enode://00ae60771d9815daba35766d463a82a7b360b3a80e35ab2e0daa25bdc6ca6213ff4c8348025e7e1a908a8f58411a364fe02a0fb3c2aa32008304f063d8aaf1a2@163.172.132.85:30303",
"enode://86ebc843aa51669e08e27400e435f957918e39dc540b021a2f3291ab776c88bbda3d97631639219b6e77e375ab7944222c47713bdeb3251b25779ce743a39d70@212.47.254.155:30303",
} }
require.Equal(t, expectedEnodes, enodes)
}, },
}, },
{ {
@ -351,236 +252,130 @@ var loadConfigTestCases = []struct {
} }
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.False(t, nodeConfig.BootClusterConfig.Enabled, "boot cluster is expected to be disabled")
} require.Empty(t, nodeConfig.BootClusterConfig.RootHash)
require.Empty(t, nodeConfig.BootClusterConfig.RootNumber)
if nodeConfig.BootClusterConfig.Enabled {
t.Fatal("boot cluster is expected to be disabled")
}
}, },
}, },
{ {
`select boot cluster (Ropsten Prod)`, `select boot cluster (Ropsten Prod)`,
`{ `{
"NetworkId": 311, "NetworkId": 3,
"DataDir": "$TMPDIR", "DataDir": "$TMPDIR",
"BootClusterConfig": { "DevMode": false
"ConfigFile": "ropsten.prod.json"
}
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.True(t, nodeConfig.BootClusterConfig.Enabled, "boot cluster is expected to be enabled by default")
} require.Equal(t, "91825fffecb5678167273955deaddbf03c26ae04287cfda61403c0bad5ceab8d", nodeConfig.BootClusterConfig.RootHash)
require.Equal(t, 259, nodeConfig.BootClusterConfig.RootNumber)
expectedConfigFile := "ropsten.prod.json" enodes := nodeConfig.BootClusterConfig.BootNodes
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
enodes, err := nodeConfig.LoadBootClusterNodes()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedEnodes := []string{ expectedEnodes := []string{
"enode://fbddff478e18292dc32b90f139bf773a08da89ffe29208e4de0091f6c589e60fccfaf16d4f4a76be49f57782c061ec8ea97078601c6f367feabda740f5ce8246@51.15.55.219:30303", "enode://7ab298cedc4185a894d21d8a4615262ec6bdce66c9b6783878258e0d5b31013d30c9038932432f70e5b2b6a5cd323bf820554fcb22fbc7b45367889522e9c449@51.15.63.93:30303",
"enode://4e5ee0487a4d8349ab9a9925b00eed0f976d98972c5a22f43fd50d1424897757032c36f273b434a4d3e013a2544eca74a9d1a0419f9f07f7bb43182a73df3690@51.15.35.110:30303", "enode://f59e8701f18c79c5cbc7618dc7bb928d44dc2f5405c7d693dad97da2d8585975942ec6fd36d3fe608bfdc7270a34a4dd00f38cfe96b2baa24f7cd0ac28d382a1@51.15.79.88:30303",
"enode://18efd9afb60443e00fed602cc0df526cd1d8543d2f6037df9380eb973d30b5fd04ac9f221053f82034581051bfd6e54356a99af2255f1a674d71d17440a6c95b@51.15.34.3:30303", "enode://e2a3587b7b41acfc49eddea9229281905d252efba0baf565cf6276df17faf04801b7879eead757da8b5be13b05f25e775ab6d857ff264bc53a89c027a657dd10@51.15.45.114:30303",
"enode://5b99c0cb372299fd3f2d94612a682990722eb7c3a252dacefc8270eb7f172fc699c1ddfad826fbfc979270538e8d89bd6919703eb9ef526eac0a45e9fb455123@51.15.56.154:30303", "enode://fe991752c4ceab8b90608fbf16d89a5f7d6d1825647d4981569ebcece1b243b2000420a5db721e214231c7a6da3543fa821185c706cbd9b9be651494ec97f56a@51.15.67.119:30303",
"enode://0e1d4d0fcfe888bf8a478b0fd89760a47733a5c04cd47de353295a6eb8dde8f54821b31196527d0c5c73a7024dc9ff34127692d237840fc09c312b3a19cd28fe@51.15.60.23:30303", "enode://482484b9198530ee2e00db89791823244ca41dcd372242e2e1297dd06f6d8dd357603960c5ad9cc8dc15fcdf0e4edd06b7ad7db590e67a0b54f798c26581ebd7@51.15.75.138:30303",
} "enode://9e99e183b5c71d51deb16e6b42ac9c26c75cfc95fff9dfae828b871b348354cbecf196dff4dd43567b26c8241b2b979cb4ea9f8dae2d9aacf86649dafe19a39a@51.15.79.176:30303",
if len(enodes) != len(expectedEnodes) { "enode://12d52c3796700fb5acff2c7d96df7bbb6d7109b67f3442ee3d99ac1c197016cddb4c3568bbeba05d39145c59c990cd64f76bc9b00d4b13f10095c49507dd4cf9@51.15.63.110:30303",
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes)) "enode://0f7c65277f916ff4379fe520b875082a56e587eb3ce1c1567d9ff94206bdb05ba167c52272f20f634cd1ebdec5d9dfeb393018bfde1595d8e64a717c8b46692f@51.15.54.150:30303",
} "enode://e006f0b2dc98e757468b67173295519e9b6d5ff4842772acb18fd055c620727ab23766c95b8ee1008dea9e8ef61e83b1515ddb3fb56dbfb9dbf1f463552a7c9f@212.47.237.127:30303",
if !reflect.DeepEqual(enodes, expectedEnodes) { "enode://d40871fc3e11b2649700978e06acd68a24af54e603d4333faecb70926ca7df93baa0b7bf4e927fcad9a7c1c07f9b325b22f6d1730e728314d0e4e6523e5cebc2@51.15.132.235:30303",
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes) "enode://ea37c9724762be7f668e15d3dc955562529ab4f01bd7951f0b3c1960b75ecba45e8c3bb3c8ebe6a7504d9a40dd99a562b13629cc8e5e12153451765f9a12a61d@163.172.189.205:30303",
"enode://88c2b24429a6f7683fbfd06874ae3f1e7c8b4a5ffb846e77c705ba02e2543789d66fc032b6606a8d8888eb6239a2abe5897ce83f78dcdcfcb027d6ea69aa6fe9@163.172.157.61:30303",
"enode://ce6854c2c77a8800fcc12600206c344b8053bb90ee3ba280e6c4f18f3141cdc5ee80bcc3bdb24cbc0e96dffd4b38d7b57546ed528c00af6cd604ab65c4d528f6@163.172.153.124:30303",
"enode://00ae60771d9815daba35766d463a82a7b360b3a80e35ab2e0daa25bdc6ca6213ff4c8348025e7e1a908a8f58411a364fe02a0fb3c2aa32008304f063d8aaf1a2@163.172.132.85:30303",
"enode://86ebc843aa51669e08e27400e435f957918e39dc540b021a2f3291ab776c88bbda3d97631639219b6e77e375ab7944222c47713bdeb3251b25779ce743a39d70@212.47.254.155:30303",
} }
require.Equal(t, expectedEnodes, enodes)
}, },
}, },
{ {
`select boot cluster (Rinkeby Dev)`, `select boot cluster (Rinkeby Dev)`,
`{ `{
"NetworkId": 311, "NetworkId": 4,
"DataDir": "$TMPDIR", "DataDir": "$TMPDIR"
"BootClusterConfig": {
"ConfigFile": "rinkeby.dev.json"
}
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.True(t, nodeConfig.BootClusterConfig.Enabled, "boot cluster is expected to be enabled by default")
} require.Equal(t, "rinkeby-dev", nodeConfig.BootClusterConfig.RootHash)
require.True(t, nodeConfig.BootClusterConfig.RootNumber >= 66)
expectedConfigFile := "rinkeby.dev.json" enodes := nodeConfig.BootClusterConfig.BootNodes
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
enodes, err := nodeConfig.LoadBootClusterNodes()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedEnodes := []string{ expectedEnodes := []string{
"enode://7512c8f6e7ffdcc723cf77e602a1de9d8cc2e8ad35db309464819122cd773857131aee390fec33894db13da730c8432bb248eed64039e3810e156e979b2847cb@51.15.78.243:30303", "enode://7512c8f6e7ffdcc723cf77e602a1de9d8cc2e8ad35db309464819122cd773857131aee390fec33894db13da730c8432bb248eed64039e3810e156e979b2847cb@51.15.78.243:30303",
"enode://1cc27a5a41130a5c8b90db5b2273dc28f7b56f3edfc0dcc57b665d451274b26541e8de49ea7a074281906a82209b9600239c981163b6ff85c3038a8e2bc5d8b8@51.15.68.93:30303", "enode://1cc27a5a41130a5c8b90db5b2273dc28f7b56f3edfc0dcc57b665d451274b26541e8de49ea7a074281906a82209b9600239c981163b6ff85c3038a8e2bc5d8b8@51.15.68.93:30303",
"enode://798d17064141b8f88df718028a8272b943d1cb8e696b3dab56519c70b77b1d3469b56b6f4ce3788457646808f5c7299e9116626f2281f30b959527b969a71e4f@51.15.75.244:30303", "enode://798d17064141b8f88df718028a8272b943d1cb8e696b3dab56519c70b77b1d3469b56b6f4ce3788457646808f5c7299e9116626f2281f30b959527b969a71e4f@51.15.75.244:30303",
} }
if len(enodes) != len(expectedEnodes) { require.Equal(t, expectedEnodes, enodes)
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
}
if !reflect.DeepEqual(enodes, expectedEnodes) {
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
}
}, },
}, },
{ {
`select boot cluster (Rinkeby Prod)`, `select boot cluster (Rinkeby Prod)`,
`{ `{
"NetworkId": 311, "NetworkId": 4,
"DataDir": "$TMPDIR", "DataDir": "$TMPDIR",
"BootClusterConfig": { "DevMode": false
"ConfigFile": "rinkeby.prod.json"
}
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.True(t, nodeConfig.BootClusterConfig.Enabled, "boot cluster is expected to be enabled by default")
} require.Equal(t, "rinkeby-prod", nodeConfig.BootClusterConfig.RootHash)
require.True(t, nodeConfig.BootClusterConfig.RootNumber >= 66)
expectedConfigFile := "rinkeby.prod.json" enodes := nodeConfig.BootClusterConfig.BootNodes
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
enodes, err := nodeConfig.LoadBootClusterNodes()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedEnodes := []string{ expectedEnodes := []string{
"enode://fda3f6273a0f2da4ac5858d1f52e5afaf9def281121be3d37558c67d4d9ca26c6ad7a0520b2cd7454120fb770e86d5760487c9924b2166e65485f606e56d60fc@51.15.69.144:30303", "enode://fda3f6273a0f2da4ac5858d1f52e5afaf9def281121be3d37558c67d4d9ca26c6ad7a0520b2cd7454120fb770e86d5760487c9924b2166e65485f606e56d60fc@51.15.69.144:30303",
"enode://ba41aa829287a0a9076d9bffed97c8ce2e491b99873288c9e886f16fd575306ac6c656db4fbf814f5a9021aec004ffa9c0ae8650f92fd10c12eeb7c364593eb3@51.15.69.147:30303", "enode://ba41aa829287a0a9076d9bffed97c8ce2e491b99873288c9e886f16fd575306ac6c656db4fbf814f5a9021aec004ffa9c0ae8650f92fd10c12eeb7c364593eb3@51.15.69.147:30303",
"enode://28ecf5272b560ca951f4cd7f1eb8bd62da5853b026b46db432c4b01797f5b0114819a090a72acd7f32685365ecd8e00450074fa0673039aefe10f3fb666e0f3f@51.15.76.249:30303", "enode://28ecf5272b560ca951f4cd7f1eb8bd62da5853b026b46db432c4b01797f5b0114819a090a72acd7f32685365ecd8e00450074fa0673039aefe10f3fb666e0f3f@51.15.76.249:30303",
} }
if len(enodes) != len(expectedEnodes) { require.Equal(t, expectedEnodes, enodes)
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
}
if !reflect.DeepEqual(enodes, expectedEnodes) {
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
}
}, },
}, },
{ {
`select boot cluster (Homestead Dev)`, `select boot cluster (Homestead Dev)`,
`{ `{
"NetworkId": 311, "NetworkId": 1,
"DataDir": "$TMPDIR", "DataDir": "$TMPDIR"
"BootClusterConfig": {
"ConfigFile": "homestead.dev.json"
}
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.True(t, nodeConfig.BootClusterConfig.Enabled, "boot cluster is expected to be enabled by default")
} require.Equal(t, "85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f", nodeConfig.BootClusterConfig.RootHash)
require.True(t, nodeConfig.BootClusterConfig.RootNumber >= 805)
expectedConfigFile := "homestead.dev.json" enodes := nodeConfig.BootClusterConfig.BootNodes
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
enodes, err := nodeConfig.LoadBootClusterNodes()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedEnodes := []string{ expectedEnodes := []string{
"enode://93833be81c3d1bdb2ae5cde258c8f82ad1011a1bea8eb49fe50b0af394d4f7f7e45974356870552f36744efd732692a64865d1e8b64114eaf89a1bad0a1903a2@51.15.64.29:30303", "enode://93833be81c3d1bdb2ae5cde258c8f82ad1011a1bea8eb49fe50b0af394d4f7f7e45974356870552f36744efd732692a64865d1e8b64114eaf89a1bad0a1903a2@51.15.64.29:30303",
"enode://d76854bc54144b2269c5316d5f00f0a194efee2fb8d31e7b1939effd7e17f25773f8dc7fda8c4eb469450799da7f39b4e364e2a278d91b53539dcbb10b139635@51.15.73.37:30303", "enode://d76854bc54144b2269c5316d5f00f0a194efee2fb8d31e7b1939effd7e17f25773f8dc7fda8c4eb469450799da7f39b4e364e2a278d91b53539dcbb10b139635@51.15.73.37:30303",
"enode://57874205931df976079e4ff8ebb5756461030fb00f73486bd5ec4ae6ed6ba98e27d09f58e59bd85281d24084a6062bc8ab514dbcdaa9678fc3001d47772e626e@51.15.75.213:30303", "enode://57874205931df976079e4ff8ebb5756461030fb00f73486bd5ec4ae6ed6ba98e27d09f58e59bd85281d24084a6062bc8ab514dbcdaa9678fc3001d47772e626e@51.15.75.213:30303",
} }
if len(enodes) != len(expectedEnodes) { require.Equal(t, expectedEnodes, enodes)
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
}
if !reflect.DeepEqual(enodes, expectedEnodes) {
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
}
}, },
}, },
{ {
`select boot cluster (Homestead Prod)`, `select boot cluster (Homestead Prod)`,
`{ `{
"NetworkId": 311, "NetworkId": 1,
"DataDir": "$TMPDIR", "DataDir": "$TMPDIR",
"BootClusterConfig": { "DevMode": false
"ConfigFile": "homestead.prod.json"
}
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.True(t, nodeConfig.BootClusterConfig.Enabled, "boot cluster is expected to be enabled by default")
} require.Equal(t, "85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f", nodeConfig.BootClusterConfig.RootHash)
require.True(t, nodeConfig.BootClusterConfig.RootNumber >= 805)
expectedConfigFile := "homestead.prod.json" enodes := nodeConfig.BootClusterConfig.BootNodes
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
enodes, err := nodeConfig.LoadBootClusterNodes()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedEnodes := []string{ expectedEnodes := []string{
"enode://f3b0e5dca730962bae814f3402b8f8a296644c33e8d7a95bd1ab313143a752c77076a03bcb76263570f2f34d4eb530f1daf5054c0990921a872a34eb505dcedf@51.15.73.129:30303", "enode://f3b0e5dca730962bae814f3402b8f8a296644c33e8d7a95bd1ab313143a752c77076a03bcb76263570f2f34d4eb530f1daf5054c0990921a872a34eb505dcedf@51.15.73.129:30303",
"enode://fce0d1c2292829b0eccce444f8943f88087ce00a5e910b157972ee1658a948d23c7a046f26567f73b2b18d126811509d7ef1de5be9b1decfcbb14738a590c477@51.15.75.187:30303", "enode://fce0d1c2292829b0eccce444f8943f88087ce00a5e910b157972ee1658a948d23c7a046f26567f73b2b18d126811509d7ef1de5be9b1decfcbb14738a590c477@51.15.75.187:30303",
"enode://3b4b9fa02ae8d54c2db51a674bc93d85649b4775f22400f74ae25e9f1c665baa3bcdd33cadd2c1a93cd08a6af984cb605fbb61ec0d750a11d48d4080298af008@51.15.77.193:30303", "enode://3b4b9fa02ae8d54c2db51a674bc93d85649b4775f22400f74ae25e9f1c665baa3bcdd33cadd2c1a93cd08a6af984cb605fbb61ec0d750a11d48d4080298af008@51.15.77.193:30303",
} }
if len(enodes) != len(expectedEnodes) { require.Equal(t, expectedEnodes, enodes)
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
}
if !reflect.DeepEqual(enodes, expectedEnodes) {
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
}
},
},
{
`select boot cluster (custom JSON, via absolute path)`,
`{
"NetworkId": 311,
"DataDir": "$TMPDIR",
"BootClusterConfig": {
"ConfigFile": "$TMPDIR/bootstrap-cluster.json"
}
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedConfigFile := filepath.Join(dataDir, "bootstrap-cluster.json")
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
enodes, err := nodeConfig.LoadBootClusterNodes()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedEnodes := []string{
"enode://foobar@41.41.41.41:30300",
"enode://foobaz@42.42.42.42:30302",
}
if len(enodes) != len(expectedEnodes) {
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
}
if !reflect.DeepEqual(enodes, expectedEnodes) {
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
}
}, },
}, },
{ {
@ -590,22 +385,9 @@ var loadConfigTestCases = []struct {
"DataDir": "$TMPDIR" "DataDir": "$TMPDIR"
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.True(t, nodeConfig.DevMode)
} require.True(t, nodeConfig.BootClusterConfig.Enabled)
if !nodeConfig.DevMode {
t.Fatalf("unexpected dev mode: expected: %v, got: %v", true, nodeConfig.DevMode)
}
if !nodeConfig.BootClusterConfig.Enabled {
t.Fatal("expected boot cluster to be enabled")
}
if nodeConfig.BootClusterConfig.ConfigFile != params.BootClusterConfigFile {
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
params.BootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
}, },
}, },
{ {
@ -616,183 +398,9 @@ var loadConfigTestCases = []struct {
"DevMode": false "DevMode": false
}`, }`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil { require.NoError(t, err)
t.Fatalf("unexpected error: %v", err) require.False(t, nodeConfig.DevMode)
} require.True(t, nodeConfig.BootClusterConfig.Enabled)
if nodeConfig.DevMode {
t.Fatalf("unexpected dev mode: expected: %v, got: %v", false, nodeConfig.DevMode)
}
if !nodeConfig.BootClusterConfig.Enabled {
t.Fatal("expected boot cluster to be enabled")
}
expectedBootClusterConfigFile := "ropsten.prod.json"
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
},
},
{
`populate bootstrap config (Homestead/Dev)`,
`{
"NetworkId": 1,
"DataDir": "$TMPDIR",
"DevMode": true
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !nodeConfig.DevMode {
t.Fatalf("unexpected dev mode: expected: %v, got: %v", true, nodeConfig.DevMode)
}
if !nodeConfig.BootClusterConfig.Enabled {
t.Fatal("expected boot cluster to be enabled")
}
expectedBootClusterConfigFile := "homestead.dev.json"
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
},
},
{
`populate bootstrap config (Homestead/Prod)`,
`{
"NetworkId": 1,
"DataDir": "$TMPDIR",
"DevMode": false
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if nodeConfig.DevMode {
t.Fatalf("unexpected dev mode: expected: %v, got: %v", false, nodeConfig.DevMode)
}
if !nodeConfig.BootClusterConfig.Enabled {
t.Fatal("expected boot cluster to be enabled")
}
expectedBootClusterConfigFile := "homestead.prod.json"
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
},
},
{
`populate bootstrap config (Ropsten/Dev)`,
`{
"NetworkId": 3,
"DataDir": "$TMPDIR"
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !nodeConfig.DevMode {
t.Fatalf("unexpected dev mode: expected: %v, got: %v", true, nodeConfig.DevMode)
}
if !nodeConfig.BootClusterConfig.Enabled {
t.Fatal("expected boot cluster to be enabled")
}
expectedBootClusterConfigFile := "ropsten.dev.json"
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
},
},
{
`populate bootstrap config (Ropsten/Prod)`,
`{
"NetworkId": 3,
"DataDir": "$TMPDIR",
"DevMode": false
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if nodeConfig.DevMode {
t.Fatalf("unexpected dev mode: expected: %v, got: %v", false, nodeConfig.DevMode)
}
if !nodeConfig.BootClusterConfig.Enabled {
t.Fatal("expected boot cluster to be enabled")
}
expectedBootClusterConfigFile := "ropsten.prod.json"
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
},
},
{
`populate bootstrap config (Rinkeby/Dev)`,
`{
"NetworkId": 4,
"DataDir": "$TMPDIR"
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !nodeConfig.DevMode {
t.Fatalf("unexpected dev mode: expected: %v, got: %v", true, nodeConfig.DevMode)
}
if !nodeConfig.BootClusterConfig.Enabled {
t.Fatal("expected boot cluster to be enabled")
}
expectedBootClusterConfigFile := "rinkeby.dev.json"
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
},
},
{
`populate bootstrap config (Rinkeby/Prod)`,
`{
"NetworkId": 4,
"DataDir": "$TMPDIR",
"DevMode": false
}`,
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if nodeConfig.DevMode {
t.Fatalf("unexpected dev mode: expected: %v, got: %v", false, nodeConfig.DevMode)
}
if !nodeConfig.BootClusterConfig.Enabled {
t.Fatal("expected boot cluster to be enabled")
}
expectedBootClusterConfigFile := "rinkeby.prod.json"
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
}
}, },
}, },
} }
@ -806,9 +414,8 @@ func TestLoadNodeConfig(t *testing.T) {
// create sample Bootstrap Cluster Config // create sample Bootstrap Cluster Config
bootstrapConfig := []byte(`["enode://foobar@41.41.41.41:30300", "enode://foobaz@42.42.42.42:30302"]`) bootstrapConfig := []byte(`["enode://foobar@41.41.41.41:30300", "enode://foobaz@42.42.42.42:30302"]`)
if err = ioutil.WriteFile(filepath.Join(tmpDir, "bootstrap-cluster.json"), bootstrapConfig, os.ModePerm); err != nil { err = ioutil.WriteFile(filepath.Join(tmpDir, "bootstrap-cluster.json"), bootstrapConfig, os.ModePerm)
t.Fatal(err) require.NoError(t, err)
}
t.Log(tmpDir) t.Log(tmpDir)
for _, testCase := range loadConfigTestCases { for _, testCase := range loadConfigTestCases {
@ -822,32 +429,24 @@ func TestLoadNodeConfig(t *testing.T) {
func TestConfigWriteRead(t *testing.T) { func TestConfigWriteRead(t *testing.T) {
configReadWrite := func(networkId uint64, refFile string) { configReadWrite := func(networkId uint64, refFile string) {
tmpDir, err := ioutil.TempDir(os.TempDir(), "geth-config-tests") tmpDir, err := ioutil.TempDir(os.TempDir(), "geth-config-tests")
if err != nil { require.Nil(t, err)
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // nolint: errcheck defer os.RemoveAll(tmpDir) // nolint: errcheck
nodeConfig, err := params.NewNodeConfig(tmpDir, networkId, true) nodeConfig, err := params.NewNodeConfig(tmpDir, networkId, true)
if err != nil { require.Nil(t, err, "cannot create new config object")
t.Fatalf("cannot create new config object: %v", err)
}
if err := nodeConfig.Save(); err != nil { err = nodeConfig.Save()
t.Fatalf("cannot persist configuration: %v", err) require.Nil(t, err, "cannot persist configuration")
}
loadedConfigData, err := ioutil.ReadFile(filepath.Join(nodeConfig.DataDir, "config.json")) loadedConfigData, err := ioutil.ReadFile(filepath.Join(nodeConfig.DataDir, "config.json"))
if err != nil { require.Nil(t, err, "cannot read configuration from disk")
t.Fatalf("cannot read configuration from disk: %v", err)
}
refConfigData := LoadFromFile(refFile) refConfigData := LoadFromFile(refFile)
refConfigData = strings.Replace(refConfigData, "$TMPDIR", nodeConfig.DataDir, -1) refConfigData = strings.Replace(refConfigData, "$TMPDIR", nodeConfig.DataDir, -1)
refConfigData = strings.Replace(refConfigData, "$VERSION", params.Version, -1) refConfigData = strings.Replace(refConfigData, "$VERSION", params.Version, -1)
if string(loadedConfigData) != refConfigData {
t.Fatalf("configuration mismatch,\nexpected: %v\ngot: %v", refConfigData, string(loadedConfigData)) require.EqualValues(t, refConfigData, loadedConfigData)
}
} }
configReadWrite(params.RinkebyNetworkID, "testdata/config.rinkeby.json") configReadWrite(params.RinkebyNetworkID, "testdata/config.rinkeby.json")

View File

@ -1,9 +1,5 @@
package params package params
import (
"github.com/ethereum/go-ethereum/common"
)
const ( const (
// ClientIdentifier is client identifier to advertise over the network // ClientIdentifier is client identifier to advertise over the network
ClientIdentifier = "StatusIM" ClientIdentifier = "StatusIM"
@ -27,11 +23,8 @@ const (
// HTTPPort is HTTP-RPC port (replaced in unit tests) // HTTPPort is HTTP-RPC port (replaced in unit tests)
HTTPPort = 8545 HTTPPort = 8545
// DevAPIModules is a list of modules to expose via any type of RPC (HTTP, IPC) during development // APIModules is a list of modules to expose via any type of RPC (HTTP, IPC, in-proc)
DevAPIModules = "db,eth,net,web3,shh,personal,admin" APIModules = "db,eth,net,web3,shh,personal,admin"
// ProdAPIModules is a list of modules to expose via any type of RPC (HTTP, IPC) in production
ProdAPIModules = "eth,net,web3,shh,personal"
// WSHost is a host interface for the websocket RPC server // WSHost is a host interface for the websocket RPC server
WSHost = "localhost" WSHost = "localhost"
@ -57,7 +50,11 @@ const (
// CHTRootConfigURL defines URL to file containing hard-coded CHT roots // CHTRootConfigURL defines URL to file containing hard-coded CHT roots
// TODO remove this hack, once CHT sync is implemented on LES side // TODO remove this hack, once CHT sync is implemented on LES side
CHTRootConfigURL = "https://gist.githubusercontent.com/farazdagi/a8d36e2818b3b2b6074d691da63a0c36/raw/" CHTRootConfigURL = "https://gist.githubusercontent.com/tiabc/83ed515fbb0c0e9d39700a6279072b6a/raw/a8c7b08488fab3c1d9139b18af33da3df823e3ff/cht.json"
// BootClusterConfigURL defines URL to file containing hard-coded CHT roots and boot nodes
// TODO remove this hack, once CHT sync is implemented on LES side
BootClusterConfigURL = "https://gist.githubusercontent.com/tiabc/83ed515fbb0c0e9d39700a6279072b6a/raw/a8c7b08488fab3c1d9139b18af33da3df823e3ff/cht.json"
// LogFile defines where to write logs to // LogFile defines where to write logs to
LogFile = "geth.log" LogFile = "geth.log"
@ -95,13 +92,4 @@ const (
// RinkebyNetworkID is id of a test network (on PoA) // RinkebyNetworkID is id of a test network (on PoA)
RinkebyNetworkID = 4 RinkebyNetworkID = 4
// BootClusterConfigFile is default config file containing boot node list (as JSON array)
BootClusterConfigFile = "ropsten.dev.json"
)
var (
RopstenNetGenesisHash = common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d")
RinkebyNetGenesisHash = common.HexToHash("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177")
MainNetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
) )

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
[
"enode://93833be81c3d1bdb2ae5cde258c8f82ad1011a1bea8eb49fe50b0af394d4f7f7e45974356870552f36744efd732692a64865d1e8b64114eaf89a1bad0a1903a2@51.15.64.29:30303",
"enode://d76854bc54144b2269c5316d5f00f0a194efee2fb8d31e7b1939effd7e17f25773f8dc7fda8c4eb469450799da7f39b4e364e2a278d91b53539dcbb10b139635@51.15.73.37:30303",
"enode://57874205931df976079e4ff8ebb5756461030fb00f73486bd5ec4ae6ed6ba98e27d09f58e59bd85281d24084a6062bc8ab514dbcdaa9678fc3001d47772e626e@51.15.75.213:30303"
]

View File

@ -1,5 +0,0 @@
[
"enode://f3b0e5dca730962bae814f3402b8f8a296644c33e8d7a95bd1ab313143a752c77076a03bcb76263570f2f34d4eb530f1daf5054c0990921a872a34eb505dcedf@51.15.73.129:30303",
"enode://fce0d1c2292829b0eccce444f8943f88087ce00a5e910b157972ee1658a948d23c7a046f26567f73b2b18d126811509d7ef1de5be9b1decfcbb14738a590c477@51.15.75.187:30303",
"enode://3b4b9fa02ae8d54c2db51a674bc93d85649b4775f22400f74ae25e9f1c665baa3bcdd33cadd2c1a93cd08a6af984cb605fbb61ec0d750a11d48d4080298af008@51.15.77.193:30303"
]

View File

@ -1,5 +0,0 @@
[
"enode://7512c8f6e7ffdcc723cf77e602a1de9d8cc2e8ad35db309464819122cd773857131aee390fec33894db13da730c8432bb248eed64039e3810e156e979b2847cb@51.15.78.243:30303",
"enode://1cc27a5a41130a5c8b90db5b2273dc28f7b56f3edfc0dcc57b665d451274b26541e8de49ea7a074281906a82209b9600239c981163b6ff85c3038a8e2bc5d8b8@51.15.68.93:30303",
"enode://798d17064141b8f88df718028a8272b943d1cb8e696b3dab56519c70b77b1d3469b56b6f4ce3788457646808f5c7299e9116626f2281f30b959527b969a71e4f@51.15.75.244:30303"
]

View File

@ -1,5 +0,0 @@
[
"enode://fda3f6273a0f2da4ac5858d1f52e5afaf9def281121be3d37558c67d4d9ca26c6ad7a0520b2cd7454120fb770e86d5760487c9924b2166e65485f606e56d60fc@51.15.69.144:30303",
"enode://ba41aa829287a0a9076d9bffed97c8ce2e491b99873288c9e886f16fd575306ac6c656db4fbf814f5a9021aec004ffa9c0ae8650f92fd10c12eeb7c364593eb3@51.15.69.147:30303",
"enode://28ecf5272b560ca951f4cd7f1eb8bd62da5853b026b46db432c4b01797f5b0114819a090a72acd7f32685365ecd8e00450074fa0673039aefe10f3fb666e0f3f@51.15.76.249:30303"
]

View File

@ -1,7 +0,0 @@
[
"enode://da3bf389a031f33fb55c9f5f54fde8473912402d27fffaa50efd74c0d0515f3a61daf6d52151f2876b19c15828e6f670352bff432b5ec457652e74755e8c864f@51.15.62.116:30303",
"enode://584c0db89b00719e9e7b1b5c32a4a8942f379f4d5d66bb69f9c7fa97fa42f64974e7b057b35eb5a63fd7973af063f9a1d32d8c60dbb4854c64cb8ab385470258@51.15.35.2:30303",
"enode://e71ba996b923e4756783375e0ed1f29963b7f759305926315d3cf9a71364d2980dbc86b1c1549812c720b38f60d347149f1ba33681c5cd4c8fca4ee8116efec6@51.15.35.70:30303",
"enode://829f09a946bcac67afbd7b8face82c48106af6a6b2507c007de6c79b2dbdf5544368afdf93cf5218d6d75a1f0219e6312db48bcc2f0fdfacb1d82c81f061d623@51.15.54.229:30303",
"enode://e80276aabb7682a4a659f4341c1199de79d91a2e500a6ee9bed16ed4ce927ba8d32ba5dea357739ffdf2c5bcc848d3064bb6f149f0b4249c1f7e53f8bf02bfc8@51.15.39.57:30303"
]

View File

@ -1,7 +0,0 @@
[
"enode://fbddff478e18292dc32b90f139bf773a08da89ffe29208e4de0091f6c589e60fccfaf16d4f4a76be49f57782c061ec8ea97078601c6f367feabda740f5ce8246@51.15.55.219:30303",
"enode://4e5ee0487a4d8349ab9a9925b00eed0f976d98972c5a22f43fd50d1424897757032c36f273b434a4d3e013a2544eca74a9d1a0419f9f07f7bb43182a73df3690@51.15.35.110:30303",
"enode://18efd9afb60443e00fed602cc0df526cd1d8543d2f6037df9380eb973d30b5fd04ac9f221053f82034581051bfd6e54356a99af2255f1a674d71d17440a6c95b@51.15.34.3:30303",
"enode://5b99c0cb372299fd3f2d94612a682990722eb7c3a252dacefc8270eb7f172fc699c1ddfad826fbfc979270538e8d89bd6919703eb9ef526eac0a45e9fb455123@51.15.56.154:30303",
"enode://0e1d4d0fcfe888bf8a478b0fd89760a47733a5c04cd47de353295a6eb8dde8f54821b31196527d0c5c73a7024dc9ff34127692d237840fc09c312b3a19cd28fe@51.15.60.23:30303"
]

View File

@ -1,6 +1,6 @@
{ {
"Node": { "Node": {
"SyncSeconds": 7, "SyncSeconds": 30,
"HTTPPort": 8645, "HTTPPort": 8645,
"WSPort": 8646 "WSPort": 8646
}, },

View File

@ -1,4 +1,4 @@
// Package static embeds static (JS, HTML) resources right into the binaries // Package static embeds static (JS, HTML) resources right into the binaries
package static package static
//go:generate go-bindata -pkg static -o bindata.go scripts/ bootcluster/ config/ keys/ testdata/... //go:generate go-bindata -pkg static -o bindata.go scripts/ config/ keys/ testdata/...

View File

@ -286,7 +286,7 @@ describe('Whisper Tests', function () {
}, 200); }, 200);
}); });
it('shh.unsubscribe(filterID)', function () { it.skip('shh.unsubscribe(filterID)', function () {
node1.shh.unsubscribe(filterid1); node1.shh.unsubscribe(filterid1);
node1.shh.unsubscribe(filterid2); node1.shh.unsubscribe(filterid2);
}); });

View File

@ -1,3 +1,6 @@
.git **/.git
**/*_test.go
build/_workspace build/_workspace
build/_bin build/_bin
tests/testdata

View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@ -0,0 +1,16 @@
## Can I have feature X
Before you do a feature request please check and make sure that it isn't possible
through some other means. The JavaScript enabled console is a powerful feature
in the right hands. Please check our [Bitchin' tricks](https://github.com/ethereum/go-ethereum/wiki/bitchin-tricks) wiki page for more info
and help.
## Contributing
If you'd like to contribute to go-ethereum please fork, fix, commit and
send a pull request. Commits which do not comply with the coding standards
are ignored (use gofmt!).
See [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
for more details on configuring your environment, testing, and
dependency management.

View File

@ -0,0 +1,20 @@
#### System information
Geth version: `geth version`
OS & Version: Windows/Linux/OSX
Commit hash : (if `develop`)
#### Expected behaviour
#### Actual behaviour
#### Steps to reproduce the behaviour
#### Backtrace
````
[backtrace]
````

32
vendor/github.com/ethereum/go-ethereum/.gitignore generated vendored Normal file
View File

@ -0,0 +1,32 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore_global
/tmp
*/**/*un~
*/**/*.test
*un~
.DS_Store
*/**/.DS_Store
.ethtest
*/**/*tx_database*
*/**/*dapps*
build/_vendor/pkg
#*
.#*
*#
*~
.project
.settings
# used by the Makefile
/build/_workspace/
/build/bin/
/geth*.zip
# travis
profile.tmp
profile.cov

3
vendor/github.com/ethereum/go-ethereum/.gitmodules generated vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "tests"]
path = tests/testdata
url = https://github.com/ethereum/tests

111
vendor/github.com/ethereum/go-ethereum/.mailmap generated vendored Normal file
View File

@ -0,0 +1,111 @@
Jeffrey Wilcke <jeffrey@ethereum.org>
Jeffrey Wilcke <jeffrey@ethereum.org> <geffobscura@gmail.com>
Jeffrey Wilcke <jeffrey@ethereum.org> <obscuren@obscura.com>
Jeffrey Wilcke <jeffrey@ethereum.org> <obscuren@users.noreply.github.com>
Viktor Trón <viktor.tron@gmail.com>
Joseph Goulden <joegoulden@gmail.com>
Nick Savers <nicksavers@gmail.com>
Maran Hidskes <maran.hidskes@gmail.com>
Taylor Gerring <taylor.gerring@gmail.com>
Taylor Gerring <taylor.gerring@gmail.com> <taylor.gerring@ethereum.org>
Bas van Kervel <bas@ethdev.com>
Bas van Kervel <bas@ethdev.com> <basvankervel@ziggo.nl>
Bas van Kervel <bas@ethdev.com> <basvankervel@gmail.com>
Bas van Kervel <bas@ethdev.com> <bas-vk@users.noreply.github.com>
Sven Ehlert <sven@ethdev.com>
Vitalik Buterin <v@buterin.com>
Marian Oancea <contact@siteshop.ro>
Christoph Jentzsch <jentzsch.software@gmail.com>
Heiko Hees <heiko@heiko.org>
Alex Leverington <alex@ethdev.com>
Alex Leverington <alex@ethdev.com> <subtly@users.noreply.github.com>
Zsolt Felföldi <zsfelfoldi@gmail.com>
Gavin Wood <i@gavwood.com>
Martin Becze <mjbecze@gmail.com>
Martin Becze <mjbecze@gmail.com> <wanderer@users.noreply.github.com>
Dimitry Khokhlov <winsvega@mail.ru>
Roman Mandeleil <roman.mandeleil@gmail.com>
Alec Perseghin <aperseghin@gmail.com>
Alon Muroch <alonmuroch@gmail.com>
Arkadiy Paronyan <arkadiy@ethdev.com>
Jae Kwon <jkwon.work@gmail.com>
Aaron Kumavis <kumavis@users.noreply.github.com>
Nick Dodson <silentcicero@outlook.com>
Jason Carver <jacarver@linkedin.com>
Jason Carver <jacarver@linkedin.com> <ut96caarrs@snkmail.com>
Joseph Chow <ethereum@outlook.com>
Joseph Chow <ethereum@outlook.com> ethers <TODO>
Enrique Fynn <enriquefynn@gmail.com>
Vincent G <caktux@gmail.com>
RJ Catalano <rj@erisindustries.com>
Nchinda Nchinda <nchinda2@gmail.com>
Aron Fischer <github@aron.guru> <homotopycolimit@users.noreply.github.com>
Vlad Gluhovsky <gluk256@users.noreply.github.com>
Ville Sundell <github@solarius.fi>
Elliot Shepherd <elliot@identitii.com>
Yohann Léon <sybiload@gmail.com>
Gregg Dourgarian <greggd@tempworks.com>
Casey Detrio <cdetrio@gmail.com>
Jens Agerberg <github@agerberg.me>
Nick Johnson <arachnid@notdot.net>
Henning Diedrich <hd@eonblast.com>
Henning Diedrich <hd@eonblast.com> Drake Burroughs <wildfyre@hotmail.com>
Felix Lange <fjl@twurst.com>
Felix Lange <fjl@twurst.com> <fjl@users.noreply.github.com>
Максим Чусовлянов <mchusovlianov@gmail.com>
Louis Holbrook <dev@holbrook.no>
Louis Holbrook <dev@holbrook.no> <nolash@users.noreply.github.com>
Thomas Bocek <tom@tomp2p.net>
Victor Tran <vu.tran54@gmail.com>
Justin Drake <drakefjustin@gmail.com>
Frank Wang <eternnoir@gmail.com>
Gary Rong <garyrong0905@gmail.com>
Guillaume Nicolas <guin56@gmail.com>

184
vendor/github.com/ethereum/go-ethereum/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,184 @@
language: go
go_import_path: github.com/ethereum/go-ethereum
sudo: false
matrix:
include:
- os: linux
dist: trusty
sudo: required
go: 1.7.6
script:
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse
- sudo modprobe fuse
- sudo chmod 666 /dev/fuse
- sudo chown root:$USER /etc/fuse.conf
- go run build/ci.go install
- go run build/ci.go test -coverage
# These are the latest Go versions.
- os: linux
dist: trusty
sudo: required
go: 1.8.3
script:
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse
- sudo modprobe fuse
- sudo chmod 666 /dev/fuse
- sudo chown root:$USER /etc/fuse.conf
- go run build/ci.go install
- go run build/ci.go test -coverage -misspell
- os: osx
go: 1.8.3
sudo: required
script:
- brew update
- brew install caskroom/cask/brew-cask
- brew cask install osxfuse
- go run build/ci.go install
- go run build/ci.go test -coverage -misspell
# This builder does the Ubuntu PPA and Linux Azure uploads
- os: linux
dist: trusty
sudo: required
go: 1.8.3
env:
- ubuntu-ppa
- azure-linux
addons:
apt:
packages:
- devscripts
- debhelper
- dput
- gcc-multilib
- fakeroot
script:
# Build for the primary platforms that Trusty can manage
- go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum
- go run build/ci.go install
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go install -arch 386
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# Switch over GCC to cross compilation (breaks 386, hence why do it here only)
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
- sudo ln -s /usr/include/asm-generic /usr/include/asm
- GOARM=5 CC=arm-linux-gnueabi-gcc go run build/ci.go install -arch arm
- GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- GOARM=6 CC=arm-linux-gnueabi-gcc go run build/ci.go install -arch arm
- GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- GOARM=7 CC=arm-linux-gnueabihf-gcc go run build/ci.go install -arch arm
- GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# This builder does the Linux Azure MIPS xgo uploads
- os: linux
dist: trusty
sudo: required
services:
- docker
go: 1.8.3
env:
- azure-linux-mips
script:
- go run build/ci.go xgo --alltools -- --targets=linux/mips --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips; do mv -f "${bin}" "${bin/-linux-mips/}"; done
- go run build/ci.go archive -arch mips -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mipsle --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mipsle; do mv -f "${bin}" "${bin/-linux-mipsle/}"; done
- go run build/ci.go archive -arch mipsle -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mips64 --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips64; do mv -f "${bin}" "${bin/-linux-mips64/}"; done
- go run build/ci.go archive -arch mips64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mips64le --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips64le; do mv -f "${bin}" "${bin/-linux-mips64le/}"; done
- go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# This builder does the Android Maven and Azure uploads
- os: linux
dist: precise # Needed for the android tools
addons:
apt:
packages:
- oracle-java8-installer
- oracle-java8-set-default
language: android
android:
components:
- platform-tools
- tools
- android-15
- android-19
- android-24
env:
- azure-android
- maven-android
before_install:
- curl https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz | tar -xz
- export PATH=`pwd`/go/bin:$PATH
- export GOROOT=`pwd`/go
- export GOPATH=$HOME/go
script:
# Build the Android archive and upload it to Maven Central and Azure
- curl https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip -o android-ndk-r14b.zip
- unzip -q android-ndk-r14b.zip && rm android-ndk-r14b.zip
- mv android-ndk-r14b $HOME
- export ANDROID_NDK=$HOME/android-ndk-r14b
- mkdir -p $GOPATH/src/github.com/ethereum
- ln -s `pwd` $GOPATH/src/github.com/ethereum
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
- os: osx
go: 1.8.3
env:
- azure-osx
- azure-ios
- cocoapods-ios
script:
- go run build/ci.go install
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
# Build the iOS framework and upload it to CocoaPods and Azure
- gem uninstall cocoapods -a -x
- gem install cocoapods
- mv ~/.cocoapods/repos/master ~/.cocoapods/repos/master.bak
- sed -i '.bak' 's/repo.join/!repo.join/g' $(dirname `gem which cocoapods`)/cocoapods/sources_manager.rb
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git clone --depth=1 https://github.com/CocoaPods/Specs.git ~/.cocoapods/repos/master && pod setup --verbose; fi
- xctool -version
- xcrun simctl list
- go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
# This builder does the Azure archive purges to avoid accumulating junk
- os: linux
dist: trusty
sudo: required
go: 1.8.3
env:
- azure-purge
script:
- go run build/ci.go purge -store gethstore/builds -days 14
install:
- go get golang.org/x/tools/cmd/cover
script:
- go run build/ci.go install
- go run build/ci.go test -coverage
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
on_success: change
on_failure: always

85
vendor/github.com/ethereum/go-ethereum/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,85 @@
# This is the official list of go-ethereum authors for copyright purposes.
Ales Katona <ales@coinbase.com>
Alex Leverington <alex@ethdev.com>
Alexandre Van de Sande <alex.vandesande@ethdev.com>
Aron Fischer <github@aron.guru>
Bas van Kervel <bas@ethdev.com>
Benjamin Brent <benjamin@benjaminbrent.com>
Brian Schroeder <bts@gmail.com>
Casey Detrio <cdetrio@gmail.com>
Christoph Jentzsch <jentzsch.software@gmail.com>
Daniel A. Nagy <nagy.da@gmail.com>
Diego Siqueira <DiSiqueira@users.noreply.github.com>
Elliot Shepherd <elliot@identitii.com>
Enrique Fynn <enriquefynn@gmail.com>
Ethan Buchman <ethan@coinculture.info>
Fabian Vogelsteller <fabian@frozeman.de>
Fabio Berger <fabioberger1991@gmail.com>
Felix Lange <fjl@twurst.com>
Frank Wang <eternnoir@gmail.com>
Gary Rong <garyrong0905@gmail.com>
Gregg Dourgarian <greggd@tempworks.com>
Guillaume Nicolas <guin56@gmail.com>
Gustav Simonsson <gustav.simonsson@gmail.com>
Hao Bryan Cheng <haobcheng@gmail.com>
Henning Diedrich <hd@eonblast.com>
Isidoro Ghezzi <isidoro.ghezzi@icloud.com>
Jae Kwon <jkwon.work@gmail.com>
Jamie Pitts <james.pitts@gmail.com>
Jason Carver <jacarver@linkedin.com>
Jeff R. Allen <jra@nella.org>
Jeffrey Wilcke <jeffrey@ethereum.org>
Jens Agerberg <github@agerberg.me>
Jonathan Brown <jbrown@bluedroplet.com>
Joseph Chow <ethereum@outlook.com>
Justin Clark-Casey <justincc@justincc.org>
Justin Drake <drakefjustin@gmail.com>
Kenji Siu <kenji@isuntv.com>
Kobi Gurkan <kobigurk@gmail.com>
Lefteris Karapetsas <lefteris@refu.co>
Leif Jurvetson <leijurv@gmail.com>
Lewis Marshall <lewis@lmars.net>
Louis Holbrook <dev@holbrook.no>
Luca Zeug <luclu@users.noreply.github.com>
Maran Hidskes <maran.hidskes@gmail.com>
Marek Kotewicz <marek.kotewicz@gmail.com>
Martin Holst Swende <martin@swende.se>
Matthew Di Ferrante <mattdf@users.noreply.github.com>
Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
Micah Zoltu <micah@zoltu.net>
Nchinda Nchinda <nchinda2@gmail.com>
Nick Dodson <silentcicero@outlook.com>
Nick Johnson <arachnid@notdot.net>
Paulo L F Casaretto <pcasaretto@gmail.com>
Peter Pratscher <pratscher@gmail.com>
Péter Szilágyi <peterke@gmail.com>
RJ Catalano <rj@erisindustries.com>
Ramesh Nair <ram@hiddentao.com>
Ricardo Catalinas Jiménez <r@untroubled.be>
Rémy Roy <remyroy@remyroy.com>
Shintaro Kaneko <kaneshin0120@gmail.com>
Stein Dekker <dekker.stein@gmail.com>
Steven Roose <stevenroose@gmail.com>
Taylor Gerring <taylor.gerring@gmail.com>
Thomas Bocek <tom@tomp2p.net>
Tosh Camille <tochecamille@gmail.com>
Valentin Wüstholz <wuestholz@users.noreply.github.com>
Victor Farazdagi <simple.square@gmail.com>
Victor Tran <vu.tran54@gmail.com>
Viktor Trón <viktor.tron@gmail.com>
Ville Sundell <github@solarius.fi>
Vincent G <caktux@gmail.com>
Vitalik Buterin <v@buterin.com>
Vivek Anand <vivekanand1101@users.noreply.github.com>
Vlad Gluhovsky <gluk256@users.noreply.github.com>
Yohann Léon <sybiload@gmail.com>
Yoichi Hirai <i@yoichihirai.com>
Zahoor Mohamed <zahoor@zahoor.in>
Zsolt Felföldi <zsfelfoldi@gmail.com>
holisticode <holistic.computing@gmail.com>
ken10100147 <sunhongping@kanjian.com>
ligi <ligi@ligi.de>
xiekeyang <xiekeyang@users.noreply.github.com>
ΞTHΞЯSPHΞЯΞ <{viktor.tron,nagydani,zsfelfoldi}@gmail.com>
Максим Чусовлянов <mchusovlianov@gmail.com>

15
vendor/github.com/ethereum/go-ethereum/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,15 @@
FROM alpine:3.5
ADD . /go-ethereum
RUN \
apk add --update git go make gcc musl-dev linux-headers && \
(cd go-ethereum && make geth) && \
cp go-ethereum/build/bin/geth /usr/local/bin/ && \
apk del git go make gcc musl-dev linux-headers && \
rm -rf /go-ethereum && rm -rf /var/cache/apk/*
EXPOSE 8545
EXPOSE 30303
EXPOSE 30303/udp
ENTRYPOINT ["geth"]

147
vendor/github.com/ethereum/go-ethereum/Makefile generated vendored Normal file
View File

@ -0,0 +1,147 @@
# This Makefile is meant to be used by people that do not usually work
# with Go source code. If you know what GOPATH is then you probably
# don't need to bother with make.
.PHONY: geth android ios geth-cross swarm evm all test clean
.PHONY: geth-linux geth-linux-386 geth-linux-amd64 geth-linux-mips64 geth-linux-mips64le
.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
GOBIN = build/bin
GO ?= latest
geth:
build/env.sh go run build/ci.go install ./cmd/geth
@echo "Done building."
@echo "Run \"$(GOBIN)/geth\" to launch geth."
swarm:
build/env.sh go run build/ci.go install ./cmd/swarm
@echo "Done building."
@echo "Run \"$(GOBIN)/swarm\" to launch swarm."
evm:
build/env.sh go run build/ci.go install ./cmd/evm
@echo "Done building."
@echo "Run \"$(GOBIN)/evm\" to start the evm."
all:
build/env.sh go run build/ci.go install
android:
build/env.sh go run build/ci.go aar --local
@echo "Done building."
@echo "Import \"$(GOBIN)/geth.aar\" to use the library."
ios:
build/env.sh go run build/ci.go xcode --local
@echo "Done building."
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
test: all
build/env.sh go run build/ci.go test
clean:
rm -fr build/_workspace/pkg/ $(GOBIN)/*
# The devtools target installs tools required for 'go generate'.
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
devtools:
env GOBIN= go get -u golang.org/x/tools/cmd/stringer
env GOBIN= go get -u github.com/jteeuwen/go-bindata/go-bindata
env GOBIN= go get -u github.com/fjl/gencodec
env GOBIN= go install ./cmd/abigen
# Cross Compilation Targets (xgo)
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
@echo "Full cross compilation done:"
@ls -ld $(GOBIN)/geth-*
geth-linux: geth-linux-386 geth-linux-amd64 geth-linux-arm geth-linux-mips64 geth-linux-mips64le
@echo "Linux cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-*
geth-linux-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/386 -v ./cmd/geth
@echo "Linux 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep 386
geth-linux-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/amd64 -v ./cmd/geth
@echo "Linux amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep amd64
geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
@echo "Linux ARM cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm
geth-linux-arm-5:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-5 -v ./cmd/geth
@echo "Linux ARMv5 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-5
geth-linux-arm-6:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-6 -v ./cmd/geth
@echo "Linux ARMv6 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-6
geth-linux-arm-7:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-7 -v ./cmd/geth
@echo "Linux ARMv7 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-7
geth-linux-arm64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm64 -v ./cmd/geth
@echo "Linux ARM64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm64
geth-linux-mips:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips --ldflags '-extldflags "-static"' -v ./cmd/geth
@echo "Linux MIPS cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips
geth-linux-mipsle:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mipsle --ldflags '-extldflags "-static"' -v ./cmd/geth
@echo "Linux MIPSle cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mipsle
geth-linux-mips64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64 --ldflags '-extldflags "-static"' -v ./cmd/geth
@echo "Linux MIPS64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips64
geth-linux-mips64le:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64le --ldflags '-extldflags "-static"' -v ./cmd/geth
@echo "Linux MIPS64le cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips64le
geth-darwin: geth-darwin-386 geth-darwin-amd64
@echo "Darwin cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-*
geth-darwin-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/386 -v ./cmd/geth
@echo "Darwin 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-* | grep 386
geth-darwin-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/amd64 -v ./cmd/geth
@echo "Darwin amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-* | grep amd64
geth-windows: geth-windows-386 geth-windows-amd64
@echo "Windows cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-*
geth-windows-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/386 -v ./cmd/geth
@echo "Windows 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep 386
geth-windows-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/geth
@echo "Windows amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep amd64

302
vendor/github.com/ethereum/go-ethereum/README.md generated vendored Normal file
View File

@ -0,0 +1,302 @@
## Go Ethereum
Official golang implementation of the Ethereum protocol.
[![API Reference](
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://godoc.org/github.com/ethereum/go-ethereum)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Automated builds are available for stable releases and the unstable master branch.
Binary archives are published at https://geth.ethereum.org/downloads/.
## Building the source
For prerequisites and detailed build instructions please read the
[Installation Instructions](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum)
on the wiki.
Building geth requires both a Go (version 1.7 or later) and a C compiler.
You can install them using your favourite package manager.
Once the dependencies are installed, run
make geth
or, to build the full suite of utilities:
make all
## Executables
The go-ethereum project comes with several wrappers/executables found in the `cmd` directory.
| Command | Description |
|:----------:|-------------|
| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default) archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) for command line options. |
| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. |
| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. |
| `disasm` | Bytecode disassembler to convert EVM (Ethereum Virtual Machine) bytecode into more user friendly assembly-like opcodes (e.g. `echo "6001" | disasm`). For details on the individual opcodes, please see pages 22-30 of the [Ethereum Yellow Paper](http://gavwood.com/paper.pdf). |
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. |
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
| `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. |
## Running geth
Going through all the possible command line flags is out of scope here (please consult our
[CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)), but we've
enumerated a few common parameter combos to get you up to speed quickly on how you can run your
own Geth instance.
### Full node on the main Ethereum network
By far the most common scenario is people wanting to simply interact with the Ethereum network:
create accounts; transfer funds; deploy and interact with contracts. For this particular use-case
the user doesn't care about years-old historical data, so we can fast-sync quickly to the current
state of the network. To do so:
```
$ geth --fast --cache=512 console
```
This command will:
* Start geth in fast sync mode (`--fast`), causing it to download more data in exchange for avoiding
processing the entire history of the Ethereum network, which is very CPU intensive.
* Bump the memory allowance of the database to 512MB (`--cache=512`), which can help significantly in
sync times especially for HDD users. This flag is optional and you can set it as high or as low as
you'd like, though we'd recommend the 512MB - 2GB range.
* Start up Geth's built-in interactive [JavaScript console](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console),
(via the trailing `console` subcommand) through which you can invoke all official [`web3` methods](https://github.com/ethereum/wiki/wiki/JavaScript-API)
as well as Geth's own [management APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs).
This too is optional and if you leave it out you can always attach to an already running Geth instance
with `geth attach`.
### Full node on the Ethereum test network
Transitioning towards developers, if you'd like to play around with creating Ethereum contracts, you
almost certainly would like to do that without any real money involved until you get the hang of the
entire system. In other words, instead of attaching to the main network, you want to join the **test**
network with your node, which is fully equivalent to the main network, but with play-Ether only.
```
$ geth --testnet --fast --cache=512 console
```
The `--fast`, `--cache` flags and `console` subcommand have the exact same meaning as above and they
are equally useful on the testnet too. Please see above for their explanations if you've skipped to
here.
Specifying the `--testnet` flag however will reconfigure your Geth instance a bit:
* Instead of using the default data directory (`~/.ethereum` on Linux for example), Geth will nest
itself one level deeper into a `testnet` subfolder (`~/.ethereum/testnet` on Linux). Note, on OSX
and Linux this also means that attaching to a running testnet node requires the use of a custom
endpoint since `geth attach` will try to attach to a production node endpoint by default. E.g.
`geth attach <datadir>/testnet/geth.ipc`. Windows users are not affected by this.
* Instead of connecting the main Ethereum network, the client will connect to the test network,
which uses different P2P bootnodes, different network IDs and genesis states.
*Note: Although there are some internal protective measures to prevent transactions from crossing
over between the main network and test network, you should make sure to always use separate accounts
for play-money and real-money. Unless you manually move accounts, Geth will by default correctly
separate the two networks and will not make any accounts available between them.*
### Configuration
As an alternative to passing the numerous flags to the `geth` binary, you can also pass a configuration file via:
```
$ geth --config /path/to/your_config.toml
```
To get an idea how the file should look like you can use the `dumpconfig` subcommand to export your existing configuration:
```
$ geth --your-favourite-flags dumpconfig
```
*Note: This works only with geth v1.6.0 and above*
#### Docker quick start
One of the quickest ways to get Ethereum up and running on your machine is by using Docker:
```
docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \
-p 8545:8545 -p 30303:30303 \
ethereum/client-go --fast --cache=512
```
This will start geth in fast sync mode with a DB memory allowance of 512MB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image.
### Programatically interfacing Geth nodes
As a developer, sooner rather than later you'll want to start interacting with Geth and the Ethereum
network via your own programs and not manually through the console. To aid this, Geth has built in
support for a JSON-RPC based APIs ([standard APIs](https://github.com/ethereum/wiki/wiki/JSON-RPC) and
[Geth specific APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs)). These can be
exposed via HTTP, WebSockets and IPC (unix sockets on unix based platforms, and named pipes on Windows).
The IPC interface is enabled by default and exposes all the APIs supported by Geth, whereas the HTTP
and WS interfaces need to manually be enabled and only expose a subset of APIs due to security reasons.
These can be turned on/off and configured as you'd expect.
HTTP based JSON-RPC API options:
* `--rpc` Enable the HTTP-RPC server
* `--rpcaddr` HTTP-RPC server listening interface (default: "localhost")
* `--rpcport` HTTP-RPC server listening port (default: 8545)
* `--rpcapi` API's offered over the HTTP-RPC interface (default: "eth,net,web3")
* `--rpccorsdomain` Comma separated list of domains from which to accept cross origin requests (browser enforced)
* `--ws` Enable the WS-RPC server
* `--wsaddr` WS-RPC server listening interface (default: "localhost")
* `--wsport` WS-RPC server listening port (default: 8546)
* `--wsapi` API's offered over the WS-RPC interface (default: "eth,net,web3")
* `--wsorigins` Origins from which to accept websockets requests
* `--ipcdisable` Disable the IPC-RPC server
* `--ipcapi` API's offered over the IPC-RPC interface (default: "admin,debug,eth,miner,net,personal,shh,txpool,web3")
* `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it)
You'll need to use your own programming environments' capabilities (libraries, tools, etc) to connect
via HTTP, WS or IPC to a Geth node configured with the above flags and you'll need to speak [JSON-RPC](http://www.jsonrpc.org/specification)
on all transports. You can reuse the same connection for multiple requests!
**Note: Please understand the security implications of opening up an HTTP/WS based transport before
doing so! Hackers on the internet are actively trying to subvert Ethereum nodes with exposed APIs!
Further, all browser tabs can access locally running webservers, so malicious webpages could try to
subvert locally available APIs!**
### Operating a private network
Maintaining your own private network is more involved as a lot of configurations taken for granted in
the official networks need to be manually set up.
#### Defining the private genesis state
First, you'll need to create the genesis state of your networks, which all nodes need to be aware of
and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`):
```json
{
"config": {
"chainId": 0,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}
```
The above fields should be fine for most purposes, although we'd recommend changing the `nonce` to
some random value so you prevent unknown remote nodes from being able to connect to you. If you'd
like to pre-fund some accounts for easier testing, you can populate the `alloc` field with account
configs:
```json
"alloc": {
"0x0000000000000000000000000000000000000001": {"balance": "111111111"},
"0x0000000000000000000000000000000000000002": {"balance": "222222222"}
}
```
With the genesis state defined in the above JSON file, you'll need to initialize **every** Geth node
with it prior to starting it up to ensure all blockchain parameters are correctly set:
```
$ geth init path/to/genesis.json
```
#### Creating the rendezvous point
With all nodes that you want to run initialized to the desired genesis state, you'll need to start a
bootstrap node that others can use to find each other in your network and/or over the internet. The
clean way is to configure and run a dedicated bootnode:
```
$ bootnode --genkey=boot.key
$ bootnode --nodekey=boot.key
```
With the bootnode online, it will display an [`enode` URL](https://github.com/ethereum/wiki/wiki/enode-url-format)
that other nodes can use to connect to it and exchange peer information. Make sure to replace the
displayed IP address information (most probably `[::]`) with your externally accessible IP to get the
actual `enode` URL.
*Note: You could also use a full fledged Geth node as a bootnode, but it's the less recommended way.*
#### Starting up your member nodes
With the bootnode operational and externally reachable (you can try `telnet <ip> <port>` to ensure
it's indeed reachable), start every subsequent Geth node pointed to the bootnode for peer discovery
via the `--bootnodes` flag. It will probably also be desirable to keep the data directory of your
private network separated, so do also specify a custom `--datadir` flag.
```
$ geth --datadir=path/to/custom/data/folder --bootnodes=<bootnode-enode-url-from-above>
```
*Note: Since your network will be completely cut off from the main and test networks, you'll also
need to configure a miner to process transactions and create new blocks for you.*
#### Running a private miner
Mining on the public Ethereum network is a complex task as it's only feasible using GPUs, requiring
an OpenCL or CUDA enabled `ethminer` instance. For information on such a setup, please consult the
[EtherMining subreddit](https://www.reddit.com/r/EtherMining/) and the [Genoil miner](https://github.com/Genoil/cpp-ethereum)
repository.
In a private network setting however, a single CPU miner instance is more than enough for practical
purposes as it can produce a stable stream of blocks at the correct intervals without needing heavy
resources (consider running on a single thread, no need for multiple ones either). To start a Geth
instance for mining, run it with all your usual flags, extended by:
```
$ geth <usual-flags> --mine --minerthreads=1 --etherbase=0x0000000000000000000000000000000000000000
```
Which will start mining bocks and transactions on a single CPU thread, crediting all proceedings to
the account specified by `--etherbase`. You can further tune the mining by changing the default gas
limit blocks converge to (`--targetgaslimit`) and the price transactions are accepted at (`--gasprice`).
## Contribution
Thank you for considering to help out with the source code! We welcome contributions from
anyone on the internet, and are grateful for even the smallest of fixes!
If you'd like to contribute to go-ethereum, please fork, fix, commit and send a pull request
for the maintainers to review and merge into the main code base. If you wish to submit more
complex changes though, please check up with the core devs first on [our gitter channel](https://gitter.im/ethereum/go-ethereum)
to ensure those changes are in line with the general philosophy of the project and/or get some
early feedback which can make both your efforts much lighter as well as our review and merge
procedures quick and simple.
Please make sure your contributions adhere to our coding guidelines:
* Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
* Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
* Pull requests need to be based on and opened against the `master` branch.
* Commit messages should be prefixed with the package(s) they modify.
* E.g. "eth, rpc: make trace configs optional"
Please see the [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
for more details on configuring your environment, managing project dependencies and testing procedures.
## License
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
[GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html), also
included in our repository in the `COPYING.LESSER` file.
The go-ethereum binaries (i.e. all code inside of the `cmd` directory) is licensed under the
[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), also included
in our repository in the `COPYING` file.

1
vendor/github.com/ethereum/go-ethereum/VERSION generated vendored Normal file
View File

@ -0,0 +1 @@
1.6.7

View File

@ -17,11 +17,9 @@
package abi package abi
import ( import (
"encoding/binary"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"math/big"
"reflect" "reflect"
"strings" "strings"
@ -67,7 +65,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
} }
method = m method = m
} }
arguments, err := method.pack(method, args...) arguments, err := method.pack(args...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -78,199 +76,6 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
return append(method.Id(), arguments...), nil return append(method.Id(), arguments...), nil
} }
// toGoSliceType parses the input and casts it to the proper slice defined by the ABI
// argument in T.
func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
index := i * 32
// The slice must, at very least be large enough for the index+32 which is exactly the size required
// for the [offset in output, size of offset].
if index+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), index+32)
}
elem := t.Type.Elem
// first we need to create a slice of the type
var refSlice reflect.Value
switch elem.T {
case IntTy, UintTy, BoolTy:
// create a new reference slice matching the element type
switch t.Type.Kind {
case reflect.Bool:
refSlice = reflect.ValueOf([]bool(nil))
case reflect.Uint8:
refSlice = reflect.ValueOf([]uint8(nil))
case reflect.Uint16:
refSlice = reflect.ValueOf([]uint16(nil))
case reflect.Uint32:
refSlice = reflect.ValueOf([]uint32(nil))
case reflect.Uint64:
refSlice = reflect.ValueOf([]uint64(nil))
case reflect.Int8:
refSlice = reflect.ValueOf([]int8(nil))
case reflect.Int16:
refSlice = reflect.ValueOf([]int16(nil))
case reflect.Int32:
refSlice = reflect.ValueOf([]int32(nil))
case reflect.Int64:
refSlice = reflect.ValueOf([]int64(nil))
default:
refSlice = reflect.ValueOf([]*big.Int(nil))
}
case AddressTy: // address must be of slice Address
refSlice = reflect.ValueOf([]common.Address(nil))
case HashTy: // hash must be of slice hash
refSlice = reflect.ValueOf([]common.Hash(nil))
case FixedBytesTy:
refSlice = reflect.ValueOf([][]byte(nil))
default: // no other types are supported
return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T)
}
var slice []byte
var size int
var offset int
if t.Type.IsSlice {
// get the offset which determines the start of this array ...
offset = int(binary.BigEndian.Uint64(output[index+24 : index+32]))
if offset+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
}
slice = output[offset:]
// ... starting with the size of the array in elements ...
size = int(binary.BigEndian.Uint64(slice[24:32]))
slice = slice[32:]
// ... and make sure that we've at the very least the amount of bytes
// available in the buffer.
if size*32 > len(slice) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32)
}
// reslice to match the required size
slice = slice[:size*32]
} else if t.Type.IsArray {
//get the number of elements in the array
size = t.Type.SliceSize
//check to make sure array size matches up
if index+32*size > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), index+32*size)
}
//slice is there for a fixed amount of times
slice = output[index : index+size*32]
}
for i := 0; i < size; i++ {
var (
inter interface{} // interface type
returnOutput = slice[i*32 : i*32+32] // the return output
)
// set inter to the correct type (cast)
switch elem.T {
case IntTy, UintTy:
inter = readInteger(t.Type.Kind, returnOutput)
case BoolTy:
inter = !allZero(returnOutput)
case AddressTy:
inter = common.BytesToAddress(returnOutput)
case HashTy:
inter = common.BytesToHash(returnOutput)
case FixedBytesTy:
inter = returnOutput
}
// append the item to our reflect slice
refSlice = reflect.Append(refSlice, reflect.ValueOf(inter))
}
// return the interface
return refSlice.Interface(), nil
}
func readInteger(kind reflect.Kind, b []byte) interface{} {
switch kind {
case reflect.Uint8:
return uint8(b[len(b)-1])
case reflect.Uint16:
return binary.BigEndian.Uint16(b[len(b)-2:])
case reflect.Uint32:
return binary.BigEndian.Uint32(b[len(b)-4:])
case reflect.Uint64:
return binary.BigEndian.Uint64(b[len(b)-8:])
case reflect.Int8:
return int8(b[len(b)-1])
case reflect.Int16:
return int16(binary.BigEndian.Uint16(b[len(b)-2:]))
case reflect.Int32:
return int32(binary.BigEndian.Uint32(b[len(b)-4:]))
case reflect.Int64:
return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
default:
return new(big.Int).SetBytes(b)
}
}
func allZero(b []byte) bool {
for _, byte := range b {
if byte != 0 {
return false
}
}
return true
}
// toGoType parses the input and casts it to the proper type defined by the ABI
// argument in T.
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
// we need to treat slices differently
if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy && t.Type.T != FunctionTy {
return toGoSlice(i, t, output)
}
index := i * 32
if index+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32)
}
// Parse the given index output and check whether we need to read
// a different offset and length based on the type (i.e. string, bytes)
var returnOutput []byte
switch t.Type.T {
case StringTy, BytesTy: // variable arrays are written at the end of the return bytes
// parse offset from which we should start reading
offset := int(binary.BigEndian.Uint64(output[index+24 : index+32]))
if offset+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32)
}
// parse the size up until we should be reading
size := int(binary.BigEndian.Uint64(output[offset+24 : offset+32]))
if offset+32+size > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size)
}
// get the bytes for this return value
returnOutput = output[offset+32 : offset+32+size]
default:
returnOutput = output[index : index+32]
}
// convert the bytes to whatever is specified by the ABI.
switch t.Type.T {
case IntTy, UintTy:
return readInteger(t.Type.Kind, returnOutput), nil
case BoolTy:
return !allZero(returnOutput), nil
case AddressTy:
return common.BytesToAddress(returnOutput), nil
case HashTy:
return common.BytesToHash(returnOutput), nil
case BytesTy, FixedBytesTy, FunctionTy:
return returnOutput, nil
case StringTy:
return string(returnOutput), nil
}
return nil, fmt.Errorf("abi: unknown type %v", t.Type.T)
}
// these variable are used to determine certain types during type assertion for // these variable are used to determine certain types during type assertion for
// assignment. // assignment.
var ( var (

View File

@ -90,7 +90,7 @@ func (b *SimulatedBackend) Rollback() {
func (b *SimulatedBackend) rollback() { func (b *SimulatedBackend) rollback() {
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {}) blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
b.pendingBlock = blocks[0] b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database) b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database))
} }
// CodeAt returns the code associated with a certain account in the blockchain. // CodeAt returns the code associated with a certain account in the blockchain.
@ -279,7 +279,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
block.AddTx(tx) block.AddTx(tx)
}) })
b.pendingBlock = blocks[0] b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database) b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database))
return nil return nil
} }

View File

@ -17,10 +17,15 @@
package abi package abi
import ( import (
"errors"
"fmt" "fmt"
"reflect" "reflect"
) )
var (
errBadBool = errors.New("abi: improperly encoded boolean value")
)
// formatSliceString formats the reflection kind with the given slice size // formatSliceString formats the reflection kind with the given slice size
// and returns a formatted string representation. // and returns a formatted string representation.
func formatSliceString(kind reflect.Kind, sliceSize int) string { func formatSliceString(kind reflect.Kind, sliceSize int) string {

View File

@ -39,7 +39,7 @@ type Method struct {
Outputs []Argument Outputs []Argument
} }
func (m Method) pack(method Method, args ...interface{}) ([]byte, error) { func (method Method) pack(args ...interface{}) ([]byte, error) {
// Make sure arguments match up and pack them // Make sure arguments match up and pack them
if len(args) != len(method.Inputs) { if len(args) != len(method.Inputs) {
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs)) return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs))

View File

@ -62,19 +62,6 @@ func U256(n *big.Int) []byte {
return math.PaddedBigBytes(math.U256(n), 32) return math.PaddedBigBytes(math.U256(n), 32)
} }
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
func packNum(value reflect.Value) []byte {
switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return U256(new(big.Int).SetUint64(value.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return U256(big.NewInt(value.Int()))
case reflect.Ptr:
return U256(value.Interface().(*big.Int))
}
return nil
}
// checks whether the given reflect value is signed. This also works for slices with a number type // checks whether the given reflect value is signed. This also works for slices with a number type
func isSigned(v reflect.Value) bool { func isSigned(v reflect.Value) bool {
switch v.Type() { switch v.Type() {

View File

@ -17,6 +17,7 @@
package abi package abi
import ( import (
"math/big"
"reflect" "reflect"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -59,8 +60,20 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
if reflectValue.Kind() == reflect.Array { if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue) reflectValue = mustArrayToByteSlice(reflectValue)
} }
return common.RightPadBytes(reflectValue.Bytes(), 32) return common.RightPadBytes(reflectValue.Bytes(), 32)
} }
panic("abi: fatal error") panic("abi: fatal error")
} }
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
func packNum(value reflect.Value) []byte {
switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return U256(new(big.Int).SetUint64(value.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return U256(big.NewInt(value.Int()))
case reflect.Ptr:
return U256(value.Interface().(*big.Int))
}
return nil
}

View File

@ -32,30 +32,30 @@ func indirect(v reflect.Value) reflect.Value {
// reflectIntKind returns the reflect using the given size and // reflectIntKind returns the reflect using the given size and
// unsignedness. // unsignedness.
func reflectIntKind(unsigned bool, size int) reflect.Kind { func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) {
switch size { switch size {
case 8: case 8:
if unsigned { if unsigned {
return reflect.Uint8 return reflect.Uint8, uint8_t
} }
return reflect.Int8 return reflect.Int8, int8_t
case 16: case 16:
if unsigned { if unsigned {
return reflect.Uint16 return reflect.Uint16, uint16_t
} }
return reflect.Int16 return reflect.Int16, int16_t
case 32: case 32:
if unsigned { if unsigned {
return reflect.Uint32 return reflect.Uint32, uint32_t
} }
return reflect.Int32 return reflect.Int32, int32_t
case 64: case 64:
if unsigned { if unsigned {
return reflect.Uint64 return reflect.Uint64, uint64_t
} }
return reflect.Int64 return reflect.Int64, int64_t
} }
return reflect.Ptr return reflect.Ptr, big_t
} }
// mustArrayToBytesSlice creates a new byte slice with the exact same size as value // mustArrayToBytesSlice creates a new byte slice with the exact same size as value

View File

@ -33,7 +33,7 @@ const (
FixedBytesTy FixedBytesTy
BytesTy BytesTy
HashTy HashTy
FixedpointTy FixedPointTy
FunctionTy FunctionTy
) )
@ -126,13 +126,11 @@ func NewType(t string) (typ Type, err error) {
switch varType { switch varType {
case "int": case "int":
typ.Kind = reflectIntKind(false, varSize) typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
typ.Type = big_t
typ.Size = varSize typ.Size = varSize
typ.T = IntTy typ.T = IntTy
case "uint": case "uint":
typ.Kind = reflectIntKind(true, varSize) typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
typ.Type = ubig_t
typ.Size = varSize typ.Size = varSize
typ.T = UintTy typ.T = UintTy
case "bool": case "bool":

View File

@ -0,0 +1,235 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library 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.
//
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package abi
import (
"encoding/binary"
"fmt"
"math/big"
"reflect"
"github.com/ethereum/go-ethereum/common"
)
// toGoSliceType parses the input and casts it to the proper slice defined by the ABI
// argument in T.
func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
index := i * 32
// The slice must, at very least be large enough for the index+32 which is exactly the size required
// for the [offset in output, size of offset].
if index+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), index+32)
}
elem := t.Type.Elem
// first we need to create a slice of the type
var refSlice reflect.Value
switch elem.T {
case IntTy, UintTy, BoolTy:
// create a new reference slice matching the element type
switch t.Type.Kind {
case reflect.Bool:
refSlice = reflect.ValueOf([]bool(nil))
case reflect.Uint8:
refSlice = reflect.ValueOf([]uint8(nil))
case reflect.Uint16:
refSlice = reflect.ValueOf([]uint16(nil))
case reflect.Uint32:
refSlice = reflect.ValueOf([]uint32(nil))
case reflect.Uint64:
refSlice = reflect.ValueOf([]uint64(nil))
case reflect.Int8:
refSlice = reflect.ValueOf([]int8(nil))
case reflect.Int16:
refSlice = reflect.ValueOf([]int16(nil))
case reflect.Int32:
refSlice = reflect.ValueOf([]int32(nil))
case reflect.Int64:
refSlice = reflect.ValueOf([]int64(nil))
default:
refSlice = reflect.ValueOf([]*big.Int(nil))
}
case AddressTy: // address must be of slice Address
refSlice = reflect.ValueOf([]common.Address(nil))
case HashTy: // hash must be of slice hash
refSlice = reflect.ValueOf([]common.Hash(nil))
case FixedBytesTy:
refSlice = reflect.ValueOf([][]byte(nil))
default: // no other types are supported
return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T)
}
var slice []byte
var size int
var offset int
if t.Type.IsSlice {
// get the offset which determines the start of this array ...
offset = int(binary.BigEndian.Uint64(output[index+24 : index+32]))
if offset+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
}
slice = output[offset:]
// ... starting with the size of the array in elements ...
size = int(binary.BigEndian.Uint64(slice[24:32]))
slice = slice[32:]
// ... and make sure that we've at the very least the amount of bytes
// available in the buffer.
if size*32 > len(slice) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32)
}
// reslice to match the required size
slice = slice[:size*32]
} else if t.Type.IsArray {
//get the number of elements in the array
size = t.Type.SliceSize
//check to make sure array size matches up
if index+32*size > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), index+32*size)
}
//slice is there for a fixed amount of times
slice = output[index : index+size*32]
}
for i := 0; i < size; i++ {
var (
inter interface{} // interface type
returnOutput = slice[i*32 : i*32+32] // the return output
err error
)
// set inter to the correct type (cast)
switch elem.T {
case IntTy, UintTy:
inter = readInteger(t.Type.Kind, returnOutput)
case BoolTy:
inter, err = readBool(returnOutput)
if err != nil {
return nil, err
}
case AddressTy:
inter = common.BytesToAddress(returnOutput)
case HashTy:
inter = common.BytesToHash(returnOutput)
case FixedBytesTy:
inter = returnOutput
}
// append the item to our reflect slice
refSlice = reflect.Append(refSlice, reflect.ValueOf(inter))
}
// return the interface
return refSlice.Interface(), nil
}
func readInteger(kind reflect.Kind, b []byte) interface{} {
switch kind {
case reflect.Uint8:
return uint8(b[len(b)-1])
case reflect.Uint16:
return binary.BigEndian.Uint16(b[len(b)-2:])
case reflect.Uint32:
return binary.BigEndian.Uint32(b[len(b)-4:])
case reflect.Uint64:
return binary.BigEndian.Uint64(b[len(b)-8:])
case reflect.Int8:
return int8(b[len(b)-1])
case reflect.Int16:
return int16(binary.BigEndian.Uint16(b[len(b)-2:]))
case reflect.Int32:
return int32(binary.BigEndian.Uint32(b[len(b)-4:]))
case reflect.Int64:
return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
default:
return new(big.Int).SetBytes(b)
}
}
func readBool(word []byte) (bool, error) {
if len(word) != 32 {
return false, fmt.Errorf("abi: fatal error: incorrect word length")
}
for i, b := range word {
if b != 0 && i != 31 {
return false, errBadBool
}
}
switch word[31] {
case 0:
return false, nil
case 1:
return true, nil
default:
return false, errBadBool
}
}
// toGoType parses the input and casts it to the proper type defined by the ABI
// argument in T.
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
// we need to treat slices differently
if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy && t.Type.T != FunctionTy {
return toGoSlice(i, t, output)
}
index := i * 32
if index+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32)
}
// Parse the given index output and check whether we need to read
// a different offset and length based on the type (i.e. string, bytes)
var returnOutput []byte
switch t.Type.T {
case StringTy, BytesTy: // variable arrays are written at the end of the return bytes
// parse offset from which we should start reading
offset := int(binary.BigEndian.Uint64(output[index+24 : index+32]))
if offset+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32)
}
// parse the size up until we should be reading
size := int(binary.BigEndian.Uint64(output[offset+24 : offset+32]))
if offset+32+size > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size)
}
// get the bytes for this return value
returnOutput = output[offset+32 : offset+32+size]
default:
returnOutput = output[index : index+32]
}
// convert the bytes to whatever is specified by the ABI.
switch t.Type.T {
case IntTy, UintTy:
return readInteger(t.Type.Kind, returnOutput), nil
case BoolTy:
return readBool(returnOutput)
case AddressTy:
return common.BytesToAddress(returnOutput), nil
case HashTy:
return common.BytesToHash(returnOutput), nil
case BytesTy, FixedBytesTy, FunctionTy:
return returnOutput, nil
case StringTy:
return string(returnOutput), nil
}
return nil, fmt.Errorf("abi: unknown type %v", t.Type.T)
}

View File

@ -38,7 +38,7 @@ var ErrNotSupported = errors.New("not supported")
var ErrInvalidPassphrase = errors.New("invalid passphrase") var ErrInvalidPassphrase = errors.New("invalid passphrase")
// ErrWalletAlreadyOpen is returned if a wallet is attempted to be opened the // ErrWalletAlreadyOpen is returned if a wallet is attempted to be opened the
// secodn time. // second time.
var ErrWalletAlreadyOpen = errors.New("wallet already open") var ErrWalletAlreadyOpen = errors.New("wallet already open")
// ErrWalletClosed is returned if a wallet is attempted to be opened the // ErrWalletClosed is returned if a wallet is attempted to be opened the

View File

@ -134,14 +134,13 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
if err != nil { if err != nil {
return err return err
} }
privkey, err := crypto.HexToECDSA(keyJSON.PrivateKey)
privkey, err := hex.DecodeString(keyJSON.PrivateKey)
if err != nil { if err != nil {
return err return err
} }
k.Address = common.BytesToAddress(addr) k.Address = common.BytesToAddress(addr)
k.PrivateKey = crypto.ToECDSA(privkey) k.PrivateKey = privkey
return nil return nil
} }

View File

@ -456,7 +456,6 @@ func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (acco
if ks.cache.hasAddress(key.Address) { if ks.cache.hasAddress(key.Address) {
return accounts.Account{}, fmt.Errorf("account already exists") return accounts.Account{}, fmt.Errorf("account already exists")
} }
return ks.importKey(key, passphrase) return ks.importKey(key, passphrase)
} }

View File

@ -259,7 +259,8 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
key := crypto.ToECDSA(keyBytes) key := crypto.ToECDSAUnsafe(keyBytes)
return &Key{ return &Key{
Id: uuid.UUID(keyId), Id: uuid.UUID(keyId),
Address: crypto.PubkeyToAddress(key.PublicKey), Address: crypto.PubkeyToAddress(key.PublicKey),

View File

@ -74,7 +74,8 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
return nil, err return nil, err
} }
ethPriv := crypto.Keccak256(plainText) ethPriv := crypto.Keccak256(plainText)
ecKey := crypto.ToECDSA(ethPriv) ecKey := crypto.ToECDSAUnsafe(ethPriv)
key = &Key{ key = &Key{
Id: nil, Id: nil,
Address: crypto.PubkeyToAddress(ecKey.PublicKey), Address: crypto.PubkeyToAddress(ecKey.PublicKey),

View File

@ -0,0 +1 @@
{"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}

View File

@ -0,0 +1 @@
{"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}

View File

@ -0,0 +1 @@
{"address":"7ef5a6135f1fd6a02593eedc869c6d41d934aef8","crypto":{"cipher":"aes-128-ctr","ciphertext":"1d0839166e7a15b9c1333fc865d69858b22df26815ccf601b28219b6192974e1","cipherparams":{"iv":"8df6caa7ff1b00c4e871f002cb7921ed"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"e5e6ef3f4ea695f496b643ebd3f75c0aa58ef4070e90c80c5d3fb0241bf1595c"},"mac":"6d16dfde774845e4585357f24bce530528bc69f4f84e1e22880d34fa45c273e5"},"id":"950077c7-71e3-4c44-a4a1-143919141ed4","version":3}

View File

@ -0,0 +1 @@
{"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}

View File

@ -0,0 +1,21 @@
This directory contains accounts for testing.
The passphrase that unlocks them is "foobar".
The "good" key files which are supposed to be loadable are:
- File: UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Address: 0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8
- File: aaa
Address: 0xf466859ead1932d743d622cb74fc058882e8648a
- File: zzz
Address: 0x289d485d9771714cce91d3393d764e1311907acc
The other files (including this README) are broken in various ways
and should not be picked up by package accounts:
- File: no-address (missing address field, otherwise same as "aaa")
- File: garbage (file with random data)
- File: empty (file with no content)
- File: swapfile~ (should be skipped)
- File: .hiddenfile (should be skipped)
- File: foo/... (should be skipped because it is a directory)

View File

@ -0,0 +1 @@
{"address":"7ef5a6135f1fd6a02593eedc869c6d41d934aef8","crypto":{"cipher":"aes-128-ctr","ciphertext":"1d0839166e7a15b9c1333fc865d69858b22df26815ccf601b28219b6192974e1","cipherparams":{"iv":"8df6caa7ff1b00c4e871f002cb7921ed"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"e5e6ef3f4ea695f496b643ebd3f75c0aa58ef4070e90c80c5d3fb0241bf1595c"},"mac":"6d16dfde774845e4585357f24bce530528bc69f4f84e1e22880d34fa45c273e5"},"id":"950077c7-71e3-4c44-a4a1-143919141ed4","version":3}

View File

@ -0,0 +1 @@
{"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}

View File

@ -0,0 +1 @@
{"address":"fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e","crypto":{"cipher":"aes-128-ctr","ciphertext":"8124d5134aa4a927c79fd852989e4b5419397566f04b0936a1eb1d168c7c68a5","cipherparams":{"iv":"e2febe17176414dd2cda28287947eb2f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"44b415ede89f3bdd6830390a21b78965f571b347a589d1d943029f016c5e8bd5"},"mac":"5e149ff25bfd9dd45746a84bb2bcd2f015f2cbca2b6d25c5de8c29617f71fe5b"},"id":"d6ac5452-2b2c-4d3c-ad80-4bf0327d971c","version":3}

Binary file not shown.

View File

@ -0,0 +1 @@
{"crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}

View File

@ -0,0 +1 @@
{"address":"0000000000000000000000000000000000000000","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}

View File

@ -0,0 +1 @@
{"address":"289d485d9771714cce91d3393d764e1311907acc","crypto":{"cipher":"aes-128-ctr","ciphertext":"faf32ca89d286b107f5e6d842802e05263c49b78d46eac74e6109e9a963378ab","cipherparams":{"iv":"558833eec4a665a8c55608d7d503407d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"d571fff447ffb24314f9513f5160246f09997b857ac71348b73e785aab40dc04"},"mac":"21edb85ff7d0dab1767b9bf498f2c3cb7be7609490756bd32300bb213b59effe"},"id":"3279afcf-55ba-43ff-8997-02dcc46a6525","version":3}

View File

@ -0,0 +1 @@
{"address":"cb61d5a9c4896fb9658090b597ef0e7be6f7b67e","Crypto":{"cipher":"aes-128-cbc","ciphertext":"6143d3192db8b66eabd693d9c4e414dcfaee52abda451af79ccf474dafb35f1bfc7ea013aa9d2ee35969a1a2e8d752d0","cipherparams":{"iv":"35337770fc2117994ecdcad026bccff4"},"kdf":"scrypt","kdfparams":{"n":262144,"r":8,"p":1,"dklen":32,"salt":"9afcddebca541253a2f4053391c673ff9fe23097cd8555d149d929e4ccf1257f"},"mac":"3f3d5af884b17a100b0b3232c0636c230a54dc2ac8d986227219b0dd89197644","version":"1"},"id":"e25f7c1f-d318-4f29-b62c-687190d4d299","version":"1"}

View File

@ -0,0 +1,28 @@
{
"test1": {
"json": {
"Crypto": {
"cipher": "aes-128-cbc",
"cipherparams": {
"iv": "35337770fc2117994ecdcad026bccff4"
},
"ciphertext": "6143d3192db8b66eabd693d9c4e414dcfaee52abda451af79ccf474dafb35f1bfc7ea013aa9d2ee35969a1a2e8d752d0",
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "9afcddebca541253a2f4053391c673ff9fe23097cd8555d149d929e4ccf1257f"
},
"mac": "3f3d5af884b17a100b0b3232c0636c230a54dc2ac8d986227219b0dd89197644",
"version": "1"
},
"address": "cb61d5a9c4896fb9658090b597ef0e7be6f7b67e",
"id": "e25f7c1f-d318-4f29-b62c-687190d4d299",
"version": "1"
},
"password": "g",
"priv": "d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d"
}
}

View File

@ -0,0 +1,97 @@
{
"wikipage_test_vector_scrypt": {
"json": {
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "83dbcc02d8ccb40e466191a123791e0e"
},
"ciphertext" : "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c",
"kdf" : "scrypt",
"kdfparams" : {
"dklen" : 32,
"n" : 262144,
"r" : 1,
"p" : 8,
"salt" : "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19"
},
"mac" : "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097"
},
"id" : "3198bc9c-6672-5ab3-d995-4942343ae5b6",
"version" : 3
},
"password": "testpassword",
"priv": "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"
},
"wikipage_test_vector_pbkdf2": {
"json": {
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "6087dab2f9fdbbfaddc31a909735c1e6"
},
"ciphertext" : "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46",
"kdf" : "pbkdf2",
"kdfparams" : {
"c" : 262144,
"dklen" : 32,
"prf" : "hmac-sha256",
"salt" : "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd"
},
"mac" : "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2"
},
"id" : "3198bc9c-6672-5ab3-d995-4942343ae5b6",
"version" : 3
},
"password": "testpassword",
"priv": "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"
},
"31_byte_key": {
"json": {
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "e0c41130a323adc1446fc82f724bca2f"
},
"ciphertext" : "9517cd5bdbe69076f9bf5057248c6c050141e970efa36ce53692d5d59a3984",
"kdf" : "scrypt",
"kdfparams" : {
"dklen" : 32,
"n" : 2,
"r" : 8,
"p" : 1,
"salt" : "711f816911c92d649fb4c84b047915679933555030b3552c1212609b38208c63"
},
"mac" : "d5e116151c6aa71470e67a7d42c9620c75c4d23229847dcc127794f0732b0db5"
},
"id" : "fecfc4ce-e956-48fd-953b-30f8b52ed66c",
"version" : 3
},
"password": "foo",
"priv": "fa7b3db73dc7dfdf8c5fbdb796d741e4488628c41fc4febd9160a866ba0f35"
},
"30_byte_key": {
"json": {
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "3ca92af36ad7c2cd92454c59cea5ef00"
},
"ciphertext" : "108b7d34f3442fc26ab1ab90ca91476ba6bfa8c00975a49ef9051dc675aa",
"kdf" : "scrypt",
"kdfparams" : {
"dklen" : 32,
"n" : 2,
"r" : 8,
"p" : 1,
"salt" : "d0769e608fb86cda848065642a9c6fa046845c928175662b8e356c77f914cd3b"
},
"mac" : "75d0e6759f7b3cefa319c3be41680ab6beea7d8328653474bd06706d4cc67420"
},
"id" : "a37e1559-5955-450d-8075-7b8931b392b2",
"version" : 3
},
"password": "foo",
"priv": "81c29e8142bb6a81bef5a92bda7a8328a5c85bb2f9542e76f9b0f94fc018"
}
}

View File

@ -0,0 +1 @@
{"address":"45dea0fb0bba44f4fcf290bba71fd57d7117cbb8","crypto":{"cipher":"aes-128-ctr","ciphertext":"b87781948a1befd247bff51ef4063f716cf6c2d3481163e9a8f42e1f9bb74145","cipherparams":{"iv":"dc4926b48a105133d2f16b96833abf1e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":2,"p":1,"r":8,"salt":"004244bbdc51cadda545b1cfa43cff9ed2ae88e08c61f1479dbb45410722f8f0"},"mac":"39990c1684557447940d4c69e06b1b82b2aceacb43f284df65c956daf3046b85"},"id":"ce541d8d-c79b-40f8-9f8c-20f59616faba","version":3}

40
vendor/github.com/ethereum/go-ethereum/appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,40 @@
os: Visual Studio 2015
# Clone directly into GOPATH.
clone_folder: C:\gopath\src\github.com\ethereum\go-ethereum
clone_depth: 5
version: "{branch}.{build}"
environment:
global:
GOPATH: C:\gopath
CC: gcc.exe
matrix:
- GETH_ARCH: amd64
MSYS2_ARCH: x86_64
MSYS2_BITS: 64
MSYSTEM: MINGW64
PATH: C:\msys64\mingw64\bin\;C:\Program Files (x86)\NSIS\;%PATH%
- GETH_ARCH: 386
MSYS2_ARCH: i686
MSYS2_BITS: 32
MSYSTEM: MINGW32
PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH%
install:
- git submodule update --init
- rmdir C:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.8.3.windows-%GETH_ARCH%.zip
- 7z x go1.8.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
- go version
- gcc --version
build_script:
- go run build\ci.go install
after_build:
- go run build\ci.go archive -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
- go run build\ci.go nsis -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
test_script:
- set CGO_ENABLED=1
- go run build\ci.go test -coverage

View File

@ -0,0 +1,49 @@
# Debian Packaging
Tagged releases and develop branch commits are available as installable Debian packages
for Ubuntu. Packages are built for the all Ubuntu versions which are supported by
Canonical:
- Trusty Tahr (14.04 LTS)
- Xenial Xerus (16.04 LTS)
- Yakkety Yak (16.10)
- Zesty Zapus (17.04)
Packages of develop branch commits have suffix -unstable and cannot be installed alongside
the stable version. Switching between release streams requires user intervention.
The packages are built and served by launchpad.net. We generate a Debian source package
for each distribution and upload it. Their builder picks up the source package, builds it
and installs the new version into the PPA repository. Launchpad requires a valid signature
by a team member for source package uploads. The signing key is stored in an environment
variable which Travis CI makes available to certain builds.
We want to build go-ethereum with the most recent version of Go, irrespective of the Go
version that is available in the main Ubuntu repository. In order to make this possible,
our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on
golang-1.8, which is co-installable alongside the regular golang package. PPA dependencies
can be edited at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies
## Building Packages Locally (for testing)
You need to run Ubuntu to do test packaging.
Add the gophers PPA and install Go 1.8 and Debian packaging tools:
$ sudo apt-add-repository ppa:gophers/ubuntu/archive
$ sudo apt-get update
$ sudo apt-get install build-essential golang-1.8 devscripts debhelper
Create the source packages:
$ go run build/ci.go debsrc -workdir dist
Then go into the source package directory for your running distribution and build the package:
$ cd dist/ethereum-unstable-1.6.0+xenial
$ dpkg-buildpackage
Built packages are placed in the dist/ directory.
$ cd ..
$ dpkg-deb -c geth-unstable_1.6.0+xenial_amd64.deb

1031
vendor/github.com/ethereum/go-ethereum/build/ci.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
{{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low
* git build of {{.Env.Commit}}
-- {{.Author}} {{.Time}}

View File

@ -0,0 +1,25 @@
Source: {{.Name}}
Section: science
Priority: extra
Maintainer: {{.Author}}
Build-Depends: debhelper (>= 8.0.0), golang-1.8
Standards-Version: 3.9.5
Homepage: https://ethereum.org
Vcs-Git: git://github.com/ethereum/go-ethereum.git
Vcs-Browser: https://github.com/ethereum/go-ethereum
Package: {{.Name}}
Architecture: any
Depends: ${misc:Depends}, {{.ExeList}}
Description: Meta-package to install geth and other tools
Meta-package to install geth and other tools
{{range .Executables}}
Package: {{$.ExeName .}}
Conflicts: {{$.ExeConflicts .}}
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Built-Using: ${misc:Built-Using}
Description: {{.Description}}
{{.Description}}
{{end}}

View File

@ -0,0 +1,14 @@
Copyright 2016 The go-ethereum Authors
go-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
go-ethereum 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.

View File

@ -0,0 +1 @@
AUTHORS

View File

@ -0,0 +1 @@
build/bin/{{.Name}} usr/bin

13
vendor/github.com/ethereum/go-ethereum/build/deb.rules generated vendored Normal file
View File

@ -0,0 +1,13 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
override_dh_auto_build:
build/env.sh /usr/lib/go-1.8/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
override_dh_auto_test:
%:
dh $@

39
vendor/github.com/ethereum/go-ethereum/build/env.sh generated vendored Executable file
View File

@ -0,0 +1,39 @@
#!/bin/sh
set -e
if [ ! -f "build/env.sh" ]; then
echo "$0 must be run from the root of the repository."
exit 2
fi
# Create fake Go workspace if it doesn't exist yet.
workspace="$PWD/build/_workspace"
root="$PWD"
ethdir="$workspace/src/github.com/ethereum"
if [ ! -L "$ethdir/go-ethereum" ]; then
mkdir -p "$ethdir"
cd "$ethdir"
ln -s ../../../../../. go-ethereum
cd "$root"
fi
# Link status-go lib
statusgodir="$workspace/src/github.com/status-im"
if [ ! -L "$statusgodir/status-go" ]; then
mkdir -p "$statusgodir"
cd "$statusgodir"
ln -s ../../../../../../../status-im/status-go status-go
cd "$root"
fi
# Set up the environment to use the workspace.
GOPATH="$workspace"
export GOPATH
# Run the command inside the workspace.
cd "$ethdir/go-ethereum"
PWD="$ethdir/go-ethereum"
# Launch the arguments with the configured environment.
exec "$@"

57
vendor/github.com/ethereum/go-ethereum/build/mvn.pom generated vendored Normal file
View File

@ -0,0 +1,57 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.ethereum</groupId>
<artifactId>geth</artifactId>
<version>{{.Version}}</version>
<packaging>aar</packaging>
<name>Android Ethereum Client</name>
<description>Android port of the go-ethereum libraries and node</description>
<url>https://github.com/ethereum/go-ethereum</url>
<inceptionYear>2015</inceptionYear>
<licenses>
<license>
<name>GNU Lesser General Public License, Version 3.0</name>
<url>https://www.gnu.org/licenses/lgpl-3.0.en.html</url>
<distribution>repo</distribution>
</license>
</licenses>
<organization>
<name>Ethereum</name>
<url>https://ethereum.org</url>
</organization>
<developers>
<developer>
<id>karalabe</id>
<name>Péter Szilágyi</name>
<email>peterke@gmail.com</email>
<url>https://github.com/karalabe</url>
<properties>
<picUrl>https://www.gravatar.com/avatar/2ecbf0f5b4b79eebf8c193e5d324357f?s=256</picUrl>
</properties>
</developer>
</developers>
<contributors>{{range .Contributors}}
<contributor>
<name>{{.Name}}</name>
<email>{{.Email}}</email>
</contributor>{{end}}
</contributors>
<issueManagement>
<system>GitHub Issues</system>
<url>https://github.com/ethereum/go-ethereum/issues/</url>
</issueManagement>
<scm>
<url>https://github.com/ethereum/go-ethereum</url>
</scm>
</project>

View File

@ -0,0 +1,24 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>ossrh</id>
<username>${env.ANDROID_SONATYPE_USERNAME}</username>
<password>${env.ANDROID_SONATYPE_PASSWORD}</password>
</server>
</servers>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.executable>gpg</gpg.executable>
<gpg.passphrase></gpg.passphrase>
</properties>
</profile>
</profiles>
</settings>

View File

@ -0,0 +1,327 @@
/**
* EnvVarUpdate.nsh
* : Environmental Variables: append, prepend, and remove entries
*
* WARNING: If you use StrFunc.nsh header then include it before this file
* with all required definitions. This is to avoid conflicts
*
* Usage:
* ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
*
* Credits:
* Version 1.0
* * Cal Turney (turnec2)
* * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
* function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
* WriteEnvStr, and un.DeleteEnvStr
* * Diego Pedroso (deguix) for StrTok
* * Kevin English (kenglish_hi) for StrContains
* * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry
* (dandaman32) for StrReplace
*
* Version 1.1 (compatibility with StrFunc.nsh)
* * techtonik
*
* http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
*
*/
!ifndef ENVVARUPDATE_FUNCTION
!define ENVVARUPDATE_FUNCTION
!verbose push
!verbose 3
!include "LogicLib.nsh"
!include "WinMessages.NSH"
!include "StrFunc.nsh"
; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
!macro _IncludeStrFunction StrFuncName
!ifndef ${StrFuncName}_INCLUDED
${${StrFuncName}}
!endif
!ifndef Un${StrFuncName}_INCLUDED
${Un${StrFuncName}}
!endif
!define un.${StrFuncName} "${Un${StrFuncName}}"
!macroend
!insertmacro _IncludeStrFunction StrTok
!insertmacro _IncludeStrFunction StrStr
!insertmacro _IncludeStrFunction StrRep
; ---------------------------------- Macro Definitions ----------------------------------------
!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
Push "${EnvVarName}"
Push "${Action}"
Push "${RegLoc}"
Push "${PathString}"
Call EnvVarUpdate
Pop "${ResultVar}"
!macroend
!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
Push "${EnvVarName}"
Push "${Action}"
Push "${RegLoc}"
Push "${PathString}"
Call un.EnvVarUpdate
Pop "${ResultVar}"
!macroend
!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
; ---------------------------------- Macro Definitions end-------------------------------------
;----------------------------------- EnvVarUpdate start----------------------------------------
!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
!define hkcu_current_user 'HKCU "Environment"'
!macro EnvVarUpdate UN
Function ${UN}EnvVarUpdate
Push $0
Exch 4
Exch $1
Exch 3
Exch $2
Exch 2
Exch $3
Exch
Exch $4
Push $5
Push $6
Push $7
Push $8
Push $9
Push $R0
/* After this point:
-------------------------
$0 = ResultVar (returned)
$1 = EnvVarName (input)
$2 = Action (input)
$3 = RegLoc (input)
$4 = PathString (input)
$5 = Orig EnvVar (read from registry)
$6 = Len of $0 (temp)
$7 = tempstr1 (temp)
$8 = Entry counter (temp)
$9 = tempstr2 (temp)
$R0 = tempChar (temp) */
; Step 1: Read contents of EnvVarName from RegLoc
;
; Check for empty EnvVarName
${If} $1 == ""
SetErrors
DetailPrint "ERROR: EnvVarName is blank"
Goto EnvVarUpdate_Restore_Vars
${EndIf}
; Check for valid Action
${If} $2 != "A"
${AndIf} $2 != "P"
${AndIf} $2 != "R"
SetErrors
DetailPrint "ERROR: Invalid Action - must be A, P, or R"
Goto EnvVarUpdate_Restore_Vars
${EndIf}
${If} $3 == HKLM
ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5
${ElseIf} $3 == HKCU
ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5
${Else}
SetErrors
DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
Goto EnvVarUpdate_Restore_Vars
${EndIf}
; Check for empty PathString
${If} $4 == ""
SetErrors
DetailPrint "ERROR: PathString is blank"
Goto EnvVarUpdate_Restore_Vars
${EndIf}
; Make sure we've got some work to do
${If} $5 == ""
${AndIf} $2 == "R"
SetErrors
DetailPrint "$1 is empty - Nothing to remove"
Goto EnvVarUpdate_Restore_Vars
${EndIf}
; Step 2: Scrub EnvVar
;
StrCpy $0 $5 ; Copy the contents to $0
; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
; after the last one are not removed here but instead in Step 3)
${If} $0 != "" ; If EnvVar is not empty ...
${Do}
${${UN}StrStr} $7 $0 " ;"
${If} $7 == ""
${ExitDo}
${EndIf}
${${UN}StrRep} $0 $0 " ;" ";" ; Remove '<space>;'
${Loop}
${Do}
${${UN}StrStr} $7 $0 "; "
${If} $7 == ""
${ExitDo}
${EndIf}
${${UN}StrRep} $0 $0 "; " ";" ; Remove ';<space>'
${Loop}
${Do}
${${UN}StrStr} $7 $0 ";;"
${If} $7 == ""
${ExitDo}
${EndIf}
${${UN}StrRep} $0 $0 ";;" ";"
${Loop}
; Remove a leading or trailing semicolon from EnvVar
StrCpy $7 $0 1 0
${If} $7 == ";"
StrCpy $0 $0 "" 1 ; Change ';<EnvVar>' to '<EnvVar>'
${EndIf}
StrLen $6 $0
IntOp $6 $6 - 1
StrCpy $7 $0 1 $6
${If} $7 == ";"
StrCpy $0 $0 $6 ; Change ';<EnvVar>' to '<EnvVar>'
${EndIf}
; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug
${EndIf}
/* Step 3. Remove all instances of the target path/string (even if "A" or "P")
$6 = bool flag (1 = found and removed PathString)
$7 = a string (e.g. path) delimited by semicolon(s)
$8 = entry counter starting at 0
$9 = copy of $0
$R0 = tempChar */
${If} $5 != "" ; If EnvVar is not empty ...
StrCpy $9 $0
StrCpy $0 ""
StrCpy $8 0
StrCpy $6 0
${Do}
${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter
${If} $7 == "" ; If we've run out of entries,
${ExitDo} ; were done
${EndIf} ;
; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
${Do}
StrCpy $R0 $7 1
${If} $R0 != " "
${ExitDo}
${EndIf}
StrCpy $7 $7 "" 1 ; Remove leading space
${Loop}
${Do}
StrCpy $R0 $7 1 -1
${If} $R0 != " "
${ExitDo}
${EndIf}
StrCpy $7 $7 -1 ; Remove trailing space
${Loop}
${If} $7 == $4 ; If string matches, remove it by not appending it
StrCpy $6 1 ; Set 'found' flag
${ElseIf} $7 != $4 ; If string does NOT match
${AndIf} $0 == "" ; and the 1st string being added to $0,
StrCpy $0 $7 ; copy it to $0 without a prepended semicolon
${ElseIf} $7 != $4 ; If string does NOT match
${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0,
StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon
${EndIf} ;
IntOp $8 $8 + 1 ; Bump counter
${Loop} ; Check for duplicates until we run out of paths
${EndIf}
; Step 4: Perform the requested Action
;
${If} $2 != "R" ; If Append or Prepend
${If} $6 == 1 ; And if we found the target
DetailPrint "Target is already present in $1. It will be removed and"
${EndIf}
${If} $0 == "" ; If EnvVar is (now) empty
StrCpy $0 $4 ; just copy PathString to EnvVar
${If} $6 == 0 ; If found flag is either 0
${OrIf} $6 == "" ; or blank (if EnvVarName is empty)
DetailPrint "$1 was empty and has been updated with the target"
${EndIf}
${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty),
StrCpy $0 $0;$4 ; append PathString
${If} $6 == 1
DetailPrint "appended to $1"
${Else}
DetailPrint "Target was appended to $1"
${EndIf}
${Else} ; If Prepend (and EnvVar is not empty),
StrCpy $0 $4;$0 ; prepend PathString
${If} $6 == 1
DetailPrint "prepended to $1"
${Else}
DetailPrint "Target was prepended to $1"
${EndIf}
${EndIf}
${Else} ; If Action = Remove
${If} $6 == 1 ; and we found the target
DetailPrint "Target was found and removed from $1"
${Else}
DetailPrint "Target was NOT found in $1 (nothing to remove)"
${EndIf}
${If} $0 == ""
DetailPrint "$1 is now empty"
${EndIf}
${EndIf}
; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change
;
ClearErrors
${If} $3 == HKLM
WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section
${ElseIf} $3 == HKCU
WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section
${EndIf}
IfErrors 0 +4
MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
DetailPrint "Could not write updated $1 to $3"
Goto EnvVarUpdate_Restore_Vars
; "Export" our change
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
EnvVarUpdate_Restore_Vars:
;
; Restore the user's variables and return ResultVar
Pop $R0
Pop $9
Pop $8
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Push $0 ; Push my $0 (ResultVar)
Exch
Pop $0 ; Restore his $0
FunctionEnd
!macroend ; EnvVarUpdate UN
!insertmacro EnvVarUpdate ""
!insertmacro EnvVarUpdate "un."
;----------------------------------- EnvVarUpdate end----------------------------------------
!verbose pop
!endif

View File

@ -0,0 +1,70 @@
# Builds a Windows installer with NSIS.
# It expects the following command line arguments:
# - OUTPUTFILE, filename of the installer (without extension)
# - MAJORVERSION, major build version
# - MINORVERSION, minor build version
# - BUILDVERSION, build id version
#
# The created installer executes the following steps:
# 1. install geth for all users
# 2. install optional development tools such as abigen
# 3. create an uninstaller
# 4. configures the Windows firewall for geth
# 5. create geth, attach and uninstall start menu entries
# 6. configures the registry that allows Windows to manage the package through its platform tools
# 7. adds the environment system wide variable ETHEREUM_SOCKET
# 8. adds the install directory to %PATH%
#
# Requirements:
# - NSIS, http://nsis.sourceforge.net/Main_Page
# - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds
# - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi)
#
# After intalling NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the
# files found in Stub.
#
# based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller
#
# TODO:
# - sign installer
CRCCheck on
!define GROUPNAME "Ethereum"
!define APPNAME "Geth"
!define DESCRIPTION "Official Go implementation of the Ethereum protocol"
!addplugindir .\
# Require admin rights on NT6+ (When UAC is turned on)
RequestExecutionLevel admin
# Use LZMA compression
SetCompressor /SOLID lzma
!include LogicLib.nsh
!include PathUpdate.nsh
!include EnvVarUpdate.nsh
!macro VerifyUserIsAdmin
UserInfo::GetAccountType
pop $0
${If} $0 != "admin" # Require admin rights on NT4+
messageBox mb_iconstop "Administrator rights required!"
setErrorLevel 740 # ERROR_ELEVATION_REQUIRED
quit
${EndIf}
!macroend
function .onInit
# make vars are global for all users since geth is installed global
setShellVarContext all
!insertmacro VerifyUserIsAdmin
${If} ${ARCH} == "amd64"
StrCpy $InstDir "$PROGRAMFILES64\${APPNAME}"
${Else}
StrCpy $InstDir "$PROGRAMFILES32\${APPNAME}"
${Endif}
functionEnd
!include install.nsh
!include uninstall.nsh

View File

@ -0,0 +1,103 @@
Name "geth ${MAJORVERSION}.${MINORVERSION}.${BUILDVERSION}" # VERSION variables set through command line arguments
InstallDir "$InstDir"
OutFile "${OUTPUTFILE}" # set through command line arguments
# Links for "Add/Remove Programs"
!define HELPURL "https://github.com/ethereum/go-ethereum/issues"
!define UPDATEURL "https://github.com/ethereum/go-ethereum/releases"
!define ABOUTURL "https://github.com/ethereum/go-ethereum#ethereum-go"
!define /date NOW "%Y%m%d"
PageEx license
LicenseData {{.License}}
PageExEnd
# Install geth binary
Section "Geth" GETH_IDX
SetOutPath $INSTDIR
file {{.Geth}}
# Create start menu launcher
createDirectory "$SMPROGRAMS\${APPNAME}"
createShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\geth.exe" "--fast" "--cache=512"
createShortCut "$SMPROGRAMS\${APPNAME}\Attach.lnk" "$INSTDIR\geth.exe" "attach" "" ""
createShortCut "$SMPROGRAMS\${APPNAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "" ""
# Firewall - remove rules (if exists)
SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)"
# Firewall - add rules
SimpleFC::AdvAddRule "Geth incoming peers (TCP:30303)" "" 6 1 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" 30303 "" "" ""
SimpleFC::AdvAddRule "Geth outgoing peers (TCP:30303)" "" 6 2 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" "" 30303 "" ""
SimpleFC::AdvAddRule "Geth UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" "" 30303 "" ""
# Set default IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc"
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\geth.ipc"
# Add instdir to PATH
Push "$INSTDIR"
Call AddToPath
SectionEnd
# Install optional develop tools.
Section /o "Development tools" DEV_TOOLS_IDX
SetOutPath $INSTDIR
{{range .DevTools}}file {{.}}
{{end}}
SectionEnd
# Return on top of stack the total size (as DWORD) of the selected/installed sections.
Var GetInstalledSize.total
Function GetInstalledSize
StrCpy $GetInstalledSize.total 0
${if} ${SectionIsSelected} ${GETH_IDX}
SectionGetSize ${GETH_IDX} $0
IntOp $GetInstalledSize.total $GetInstalledSize.total + $0
${endif}
${if} ${SectionIsSelected} ${DEV_TOOLS_IDX}
SectionGetSize ${DEV_TOOLS_IDX} $0
IntOp $GetInstalledSize.total $GetInstalledSize.total + $0
${endif}
IntFmt $GetInstalledSize.total "0x%08X" $GetInstalledSize.total
Push $GetInstalledSize.total
FunctionEnd
# Write registry, Windows uses these values in various tools such as add/remove program.
# PowerShell: Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, InstallLocation, InstallDate | Format-Table AutoSize
function .onInstSuccess
# Save information in registry in HKEY_LOCAL_MACHINE branch, Windows add/remove functionality depends on this
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayName" "${GROUPNAME} - ${APPNAME} - ${DESCRIPTION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "InstallLocation" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "InstallDate" "${NOW}"
# Wait for Alex
#WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\logo.ico$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "Publisher" "${GROUPNAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "HelpLink" "${HELPURL}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "URLUpdateInfo" "${UPDATEURL}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "URLInfoAbout" "${ABOUTURL}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayVersion" "${MAJORVERSION}.${MINORVERSION}.${BUILDVERSION}"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "VersionMajor" ${MAJORVERSION}
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "VersionMinor" ${MINORVERSION}
# There is no option for modifying or repairing the install
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "NoRepair" 1
Call GetInstalledSize
Pop $0
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "EstimatedSize" "$0"
# Create uninstaller
writeUninstaller "$INSTDIR\uninstall.exe"
functionEnd
Page components
Page directory
Page instfiles

View File

@ -0,0 +1,153 @@
!include "WinMessages.nsh"
; see https://support.microsoft.com/en-us/kb/104011
!define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
; HKEY_LOCAL_MACHINE = 0x80000002
; AddToPath - Appends dir to PATH
; (does not work on Win9x/ME)
;
; Usage:
; Push "dir"
; Call AddToPath
Function AddToPath
Exch $0
Push $1
Push $2
Push $3
Push $4
; NSIS ReadRegStr returns empty string on string overflow
; Native calls are used here to check actual length of PATH
; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3)
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
IntCmp $4 0 0 done done
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2))
; RegCloseKey($3)
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
System::Call "advapi32::RegCloseKey(i $3)"
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA
DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}"
Goto done
IntCmp $4 0 +5 ; $4 != NO_ERROR
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND
DetailPrint "AddToPath: unexpected error code $4"
Goto done
StrCpy $1 ""
; Check if already in PATH
Push "$1;"
Push "$0;"
Call StrStr
Pop $2
StrCmp $2 "" 0 done
Push "$1;"
Push "$0\;"
Call StrStr
Pop $2
StrCmp $2 "" 0 done
; Prevent NSIS string overflow
StrLen $2 $0
StrLen $3 $1
IntOp $2 $2 + $3
IntOp $2 $2 + 2 ; $2 = strlen(dir) + strlen(PATH) + sizeof(";")
IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0
DetailPrint "AddToPath: new length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK "PATH not updated, new length $2 > ${NSIS_MAX_STRLEN}."
Goto done
; Append dir to PATH
DetailPrint "Add to PATH: $0"
StrCpy $2 $1 1 -1
StrCmp $2 ";" 0 +2
StrCpy $1 $1 -1 ; remove trailing ';'
StrCmp $1 "" +2 ; no leading ';'
StrCpy $0 "$1;$0"
WriteRegExpandStr ${Environ} "PATH" $0
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
done:
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
; RemoveFromPath - Removes dir from PATH
;
; Usage:
; Push "dir"
; Call RemoveFromPath
Function un.RemoveFromPath
Exch $0
Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
; NSIS ReadRegStr returns empty string on string overflow
; Native calls are used here to check actual length of PATH
; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3)
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
IntCmp $4 0 0 done done
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2))
; RegCloseKey($3)
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
System::Call "advapi32::RegCloseKey(i $3)"
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA
DetailPrint "RemoveFromPath: original length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}"
Goto done
IntCmp $4 0 +5 ; $4 != NO_ERROR
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND
DetailPrint "RemoveFromPath: unexpected error code $4"
Goto done
StrCpy $1 ""
; length < ${NSIS_MAX_STRLEN} -> ReadRegStr can be used
ReadRegStr $1 ${Environ} "PATH"
StrCpy $5 $1 1 -1
StrCmp $5 ";" +2
StrCpy $1 "$1;" ; ensure trailing ';'
Push $1
Push "$0;"
Call un.StrStr
Pop $2 ; pos of our dir
StrCmp $2 "" done
DetailPrint "Remove from PATH: $0"
StrLen $3 "$0;"
StrLen $4 $2
StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove
StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove
StrCpy $3 "$5$6"
StrCpy $5 $3 1 -1
StrCmp $5 ";" 0 +2
StrCpy $3 $3 -1 ; remove trailing ';'
WriteRegExpandStr ${Environ} "PATH" $3
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
done:
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,33 @@
Section "Uninstall"
# uninstall for all users
setShellVarContext all
# Delete (optionally) installed files
{{range $}}Delete $INSTDIR\{{.}}
{{end}}
Delete $INSTDIR\uninstall.exe
# Delete install directory
rmDir $INSTDIR
# Delete start menu launcher
Delete "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk"
Delete "$SMPROGRAMS\${APPNAME}\Attach.lnk"
Delete "$SMPROGRAMS\${APPNAME}\Uninstall.lnk"
rmDir "$SMPROGRAMS\${APPNAME}"
# Firewall - remove rules if exists
SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)"
# Remove IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc"
# Remove install directory from PATH
Push "$INSTDIR"
Call un.RemoveFromPath
# Cleanup registry (deletes all sub keys)
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}"
SectionEnd

View File

@ -0,0 +1,22 @@
Pod::Spec.new do |spec|
spec.name = 'Geth'
spec.version = '{{.Version}}'
spec.license = { :type => 'GNU Lesser General Public License, Version 3.0' }
spec.homepage = 'https://github.com/ethereum/go-ethereum'
spec.authors = { {{range .Contributors}}
'{{.Name}}' => '{{.Email}}',{{end}}
}
spec.summary = 'iOS Ethereum Client'
spec.source = { :git => 'https://github.com/ethereum/go-ethereum.git', :commit => '{{.Commit}}' }
spec.platform = :ios
spec.ios.deployment_target = '9.0'
spec.ios.vendored_frameworks = 'Frameworks/Geth.framework'
spec.prepare_command = <<-CMD
curl https://gethstore.blob.core.windows.net/builds/{{.Archive}}.tar.gz | tar -xvz
mkdir Frameworks
mv {{.Archive}}/Geth.framework Frameworks
rm -rf {{.Archive}}
CMD
end

Some files were not shown because too many files have changed in this diff Show More