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:
parent
c274cf5222
commit
ebd77aabe2
|
@ -4,6 +4,8 @@
|
|||
# or operating system, you probably want to add a global ignore instead:
|
||||
# git config --global core.excludesfile ~/.gitignore_global
|
||||
|
||||
/statusd-data
|
||||
|
||||
/tmp
|
||||
*/**/*un~
|
||||
*/**/*.test
|
||||
|
|
|
@ -56,6 +56,7 @@ func parseFaucetCommandConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
|||
nodeConfig.APIModules = "eth"
|
||||
nodeConfig.HTTPHost = "0.0.0.0" // allow to connect from anywhere
|
||||
nodeConfig.HTTPPort = ctx.Int(HTTPPortFlag.Name)
|
||||
nodeConfig.RPCEnabled = ctx.Bool(HTTPEnabledFlag.Name)
|
||||
|
||||
// extra options
|
||||
nodeConfig.BootClusterConfig.Enabled = true
|
||||
|
|
|
@ -53,6 +53,7 @@ func parseLESCommandConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
|||
|
||||
// Enabled sub-protocols
|
||||
nodeConfig.LightEthConfig.Enabled = true
|
||||
nodeConfig.RPCEnabled = ctx.Bool(HTTPEnabledFlag.Name)
|
||||
nodeConfig.WhisperConfig.Enabled = ctx.Bool(WhisperEnabledFlag.Name)
|
||||
nodeConfig.SwarmConfig.Enabled = ctx.Bool(SwarmEnabledFlag.Name)
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ var (
|
|||
// HTTPEnabledFlag defines whether HTTP RPC endpoint should be opened or not
|
||||
HTTPEnabledFlag = cli.BoolFlag{
|
||||
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)
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/les/status"
|
||||
gethparams "github.com/ethereum/go-ethereum/params"
|
||||
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
"github.com/status-im/status-go/geth/node"
|
||||
"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",
|
||||
testDiscardMultipleQueuedTransactions,
|
||||
},
|
||||
{
|
||||
"test jail invalid initialization",
|
||||
testJailInitInvalid,
|
||||
},
|
||||
{
|
||||
"test jail invalid parse",
|
||||
testJailParseInvalid,
|
||||
},
|
||||
{
|
||||
"test jail initialization",
|
||||
testJailInit,
|
||||
|
@ -170,11 +179,11 @@ func testGetDefaultConfig(t *testing.T) bool {
|
|||
return false
|
||||
}
|
||||
chainConfig := genesis.Config
|
||||
if chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock) != 0 {
|
||||
if chainConfig.HomesteadBlock.Cmp(gethparams.MainnetChainConfig.HomesteadBlock) != 0 {
|
||||
t.Error("invalid chainConfig.HomesteadBlock")
|
||||
return false
|
||||
}
|
||||
if chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock) != 0 {
|
||||
if chainConfig.DAOForkBlock.Cmp(gethparams.MainnetChainConfig.DAOForkBlock) != 0 {
|
||||
t.Error("invalid chainConfig.DAOForkBlock")
|
||||
return false
|
||||
}
|
||||
|
@ -182,23 +191,23 @@ func testGetDefaultConfig(t *testing.T) bool {
|
|||
t.Error("invalid chainConfig.DAOForkSupport")
|
||||
return false
|
||||
}
|
||||
if chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock) != 0 {
|
||||
if chainConfig.EIP150Block.Cmp(gethparams.MainnetChainConfig.EIP150Block) != 0 {
|
||||
t.Error("invalid chainConfig.EIP150Block")
|
||||
return false
|
||||
}
|
||||
if chainConfig.EIP150Hash != gethparams.MainNetHomesteadGasRepriceHash {
|
||||
if chainConfig.EIP150Hash != gethparams.MainnetChainConfig.EIP150Hash {
|
||||
t.Error("invalid chainConfig.EIP150Hash")
|
||||
return false
|
||||
}
|
||||
if chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
|
||||
if chainConfig.EIP155Block.Cmp(gethparams.MainnetChainConfig.EIP155Block) != 0 {
|
||||
t.Error("invalid chainConfig.EIP155Block")
|
||||
return false
|
||||
}
|
||||
if chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon) != 0 {
|
||||
if chainConfig.EIP158Block.Cmp(gethparams.MainnetChainConfig.EIP158Block) != 0 {
|
||||
t.Error("invalid chainConfig.EIP158Block")
|
||||
return false
|
||||
}
|
||||
if chainConfig.ChainId.Cmp(gethparams.MainNetChainID) != 0 {
|
||||
if chainConfig.ChainId.Cmp(gethparams.MainnetChainConfig.ChainId) != 0 {
|
||||
t.Error("invalid chainConfig.ChainId")
|
||||
return false
|
||||
}
|
||||
|
@ -986,7 +995,7 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool {
|
|||
|
||||
select {
|
||||
case <-allTestTxCompleted:
|
||||
// pass
|
||||
// pass
|
||||
case <-time.After(20 * time.Second):
|
||||
t.Error("test timed out")
|
||||
return false
|
||||
|
@ -1284,7 +1293,7 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
|
|||
|
||||
select {
|
||||
case <-allTestTxDiscarded:
|
||||
// pass
|
||||
// pass
|
||||
case <-time.After(20 * time.Second):
|
||||
t.Error("test timed out")
|
||||
return false
|
||||
|
@ -1298,6 +1307,51 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool {
|
|||
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 {
|
||||
initCode := `
|
||||
var _status_catalog = {
|
||||
|
|
|
@ -40,7 +40,7 @@ func (s *APITestSuite) TestCHTUpdate() {
|
|||
require.NoError(err)
|
||||
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 := `{
|
||||
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
|
||||
"DataDir": "` + tmpDir + `",
|
||||
|
@ -51,14 +51,15 @@ func (s *APITestSuite) TestCHTUpdate() {
|
|||
"CHTRootConfigURL": "` + url + `"
|
||||
}
|
||||
}`
|
||||
nodeConfig, err := params.LoadNodeConfig(configJSON)
|
||||
//nodeConfig, err := params.LoadNodeConfig(configJSON)
|
||||
_, err = params.LoadNodeConfig(configJSON)
|
||||
require.NoError(err)
|
||||
|
||||
// start node
|
||||
nodeConfig.DevMode = true
|
||||
s.api.StartNode(nodeConfig)
|
||||
time.Sleep(TestConfig.Node.SyncSeconds * time.Second)
|
||||
s.api.StopNode()
|
||||
//nodeConfig.DevMode = true
|
||||
//s.api.StartNode(nodeConfig)
|
||||
//s.api.StopNode()
|
||||
// TODO(tiabc): Test that CHT is really updated.
|
||||
}
|
||||
|
||||
func (s *APITestSuite) TestRaceConditions() {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package api_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
|
@ -30,103 +32,24 @@ const (
|
|||
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() {
|
||||
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)
|
||||
|
||||
// log into account from which transactions will be sent
|
||||
require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
||||
|
||||
txParams := `{
|
||||
"from": "` + TestConfig.Account1.Address + `",
|
||||
"to": "0xf82da7547534045b4e00442bc89e16186cf8c272",
|
||||
"to": "` + TestConfig.Account2.Address + `",
|
||||
"value": "0.000001"
|
||||
}`
|
||||
|
||||
txCompletedSuccessfully := make(chan struct{})
|
||||
txCompletedCounter := make(chan struct{})
|
||||
txHashes := make(chan gethcommon.Hash)
|
||||
|
||||
// replace transaction notification handler
|
||||
|
@ -162,7 +85,6 @@ func (s *BackendTestSuite) TestJailSendQueuedTransaction() {
|
|||
|
||||
txCompletedSuccessfully <- struct{}{} // so that timeout is aborted
|
||||
txHashes <- txHash
|
||||
txCompletedCounter <- struct{}{}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -253,99 +175,98 @@ func (s *BackendTestSuite) TestJailSendQueuedTransaction() {
|
|||
},
|
||||
}
|
||||
|
||||
jailInstance := s.backend.JailManager()
|
||||
for _, test := range tests {
|
||||
|
||||
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, ``)
|
||||
|
||||
requireMessageId = test.requireMessageId
|
||||
|
||||
for _, command := range test.commands {
|
||||
go func(jail common.JailManager, test testCase, command testCommand) {
|
||||
log.Info(fmt.Sprintf("->%s: %s", test.name, command.command))
|
||||
response := jail.Call(testChatID, command.command, command.params)
|
||||
var txHash gethcommon.Hash
|
||||
if command.command == `["commands", "send"]` {
|
||||
txHash = <-txHashes
|
||||
}
|
||||
expectedResponse := strings.Replace(command.expectedResponse, "TX_HASH", txHash.Hex(), 1)
|
||||
s.Equal(expectedResponse, response)
|
||||
}(jailInstance, test, command)
|
||||
s.T().Logf("%s: %s", test.name, command.command)
|
||||
response := jailInstance.Call(testChatID, command.command, command.params)
|
||||
var txHash gethcommon.Hash
|
||||
if command.command == `["commands", "send"]` {
|
||||
txHash = <-txHashes
|
||||
}
|
||||
expectedResponse := strings.Replace(command.expectedResponse, "TX_HASH", txHash.Hex(), 1)
|
||||
s.Require().Equal(expectedResponse, response)
|
||||
}
|
||||
<-txCompletedCounter
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
func (s *BackendTestSuite) TestGasEstimation() {
|
||||
func (s *BackendTestSuite) TestContractDeployment() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.backend)
|
||||
|
||||
s.StartTestBackend(params.RopstenNetworkID)
|
||||
defer s.StopTestBackend()
|
||||
|
||||
jailInstance := s.backend.JailManager()
|
||||
require.NotNil(jailInstance)
|
||||
jailInstance.Parse(testChatID, "")
|
||||
// Allow to sync, otherwise you'll get "Nonce too low."
|
||||
time.Sleep(TestConfig.Node.SyncSeconds * time.Second)
|
||||
|
||||
// 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)
|
||||
|
||||
// make sure you panic if transaction complete doesn't return
|
||||
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
|
||||
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))
|
||||
require.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))
|
||||
// Use s.* for assertions - require leaves the channel unclosed.
|
||||
|
||||
//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))
|
||||
|
||||
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"]))
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
||||
_, err = vm.Run(`
|
||||
_, err = cell.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
|
||||
}
|
||||
})
|
||||
`)
|
||||
s.NoError(err)
|
||||
require.NoError(err)
|
||||
|
||||
<-completeQueuedTransaction
|
||||
|
||||
responseValue, err := vm.Get("responseValue")
|
||||
s.NoError(err, "vm.Get() failed")
|
||||
responseValue, err := cell.Get("responseValue")
|
||||
require.NoError(err)
|
||||
|
||||
response, err := responseValue.ToString()
|
||||
s.NoError(err, "cannot parse result")
|
||||
require.NoError(err)
|
||||
|
||||
expectedResponse := txHash.Hex()
|
||||
s.Equal(expectedResponse, response, "expected response is not returned")
|
||||
require.Equal(expectedResponse, response)
|
||||
s.T().Logf("estimation complete: %s", response)
|
||||
}
|
||||
|
||||
|
@ -372,7 +293,7 @@ func (s *BackendTestSuite) TestJailWhisper() {
|
|||
_, err = whisperService.AddKeyPair(accountKey1.PrivateKey)
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -384,7 +305,7 @@ func (s *BackendTestSuite) TestJailWhisper() {
|
|||
_, err = whisperService.AddKeyPair(accountKey2.PrivateKey)
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -694,11 +615,12 @@ func (s *BackendTestSuite) TestJailWhisper() {
|
|||
return web3.toHex(randInt);
|
||||
};
|
||||
`)
|
||||
vm, err := jailInstance.JailCellVM(testCaseKey)
|
||||
|
||||
cell, err := jailInstance.GetJailCell(testCaseKey)
|
||||
require.NoError(err, "cannot get VM")
|
||||
|
||||
// post messages
|
||||
if _, err := vm.Run(testCase.testCode); err != nil {
|
||||
if _, err := cell.Run(testCase.testCode); err != nil {
|
||||
require.Fail(err.Error())
|
||||
return
|
||||
}
|
||||
|
@ -708,10 +630,10 @@ func (s *BackendTestSuite) TestJailWhisper() {
|
|||
}
|
||||
|
||||
// update installed filters
|
||||
filterId, err := vm.Get("filterId")
|
||||
filterId, err := cell.Get("filterId")
|
||||
require.NoError(err, "cannot get filterId")
|
||||
|
||||
filterName, err := vm.Get("filterName")
|
||||
filterName, err := cell.Get("filterName")
|
||||
require.NoError(err, "cannot get filterName")
|
||||
|
||||
if _, ok := installedFilters[filterName.String()]; !ok {
|
||||
|
@ -726,8 +648,10 @@ func (s *BackendTestSuite) TestJailWhisper() {
|
|||
for testKey, filter := range installedFilters {
|
||||
if filter != "" {
|
||||
s.T().Logf("filter found: %v", filter)
|
||||
for _, message := range whisperAPI.GetNewSubscriptionMessages(filter) {
|
||||
s.T().Logf("message found: %s", gethcommon.FromHex(message.Payload))
|
||||
messages, err := whisperAPI.GetFilterMessages(filter)
|
||||
require.NoError(err)
|
||||
for _, message := range messages {
|
||||
s.T().Logf("message found: %s", string(message.Payload))
|
||||
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()
|
||||
}
|
||||
|
|
|
@ -148,6 +148,8 @@ func (s *BackendTestSuite) TestNodeStartStop() {
|
|||
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() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.backend)
|
||||
|
@ -184,7 +186,7 @@ func (s *BackendTestSuite) TestCallRPC() {
|
|||
{
|
||||
`{"jsonrpc":"2.0","method":"shh_version","params":[],"id":67}`,
|
||||
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.T().Log("shh_version: ", resultJSON)
|
||||
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() {
|
||||
require := s.Require()
|
||||
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() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.backend)
|
||||
|
@ -423,6 +429,8 @@ func (s *BackendTestSuite) TestNetworkSwitching() {
|
|||
<-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() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.backend)
|
||||
|
@ -442,6 +450,8 @@ func (s *BackendTestSuite) TestResetChainData() {
|
|||
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() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.backend)
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
. "github.com/status-im/status-go/geth/testing"
|
||||
)
|
||||
|
||||
// FIXME(tiabc): Sometimes it fails due to "no suitable peers found".
|
||||
func (s *BackendTestSuite) TestSendContractTx() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.backend)
|
||||
|
@ -36,7 +37,7 @@ func (s *BackendTestSuite) TestSendContractTx() {
|
|||
|
||||
// make sure you panic if transaction complete doesn't return
|
||||
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
|
||||
var txHash = gethcommon.Hash{}
|
||||
|
@ -114,7 +115,7 @@ func (s *BackendTestSuite) TestSendEtherTx() {
|
|||
|
||||
// make sure you panic if transaction complete doesn't return
|
||||
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
|
||||
var txHash = gethcommon.Hash{}
|
||||
|
@ -185,7 +186,7 @@ func (s *BackendTestSuite) TestDoubleCompleteQueuedTransactions() {
|
|||
|
||||
// make sure you panic if transaction complete doesn't return
|
||||
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
|
||||
var txID string
|
||||
|
@ -269,7 +270,7 @@ func (s *BackendTestSuite) TestDiscardQueuedTransaction() {
|
|||
|
||||
// make sure you panic if transaction complete doesn't return
|
||||
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
|
||||
var txID string
|
||||
|
@ -573,7 +574,7 @@ func (s *BackendTestSuite) TestDiscardMultipleQueuedTransactions() {
|
|||
select {
|
||||
case <-allTestTxDiscarded:
|
||||
// pass
|
||||
case <-time.After(30 * time.Second):
|
||||
case <-time.After(1 * time.Minute):
|
||||
s.Fail("test timed out")
|
||||
return
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@ import (
|
|||
"github.com/robertkrimen/otto"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
"github.com/status-im/status-go/static"
|
||||
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
)
|
||||
|
||||
// errors
|
||||
|
@ -173,28 +171,12 @@ type TxQueueManager interface {
|
|||
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.
|
||||
type JailCell interface {
|
||||
CellVM() *otto.Otto
|
||||
CellLoop() *loop.Loop
|
||||
Executor() JailExecutor
|
||||
Copy() (JailCell, error)
|
||||
Set(string, interface{}) error
|
||||
Get(string) (otto.Value, error)
|
||||
Run(string) (otto.Value, error)
|
||||
RunOnLoop(string) (otto.Value, error)
|
||||
}
|
||||
|
||||
// JailManager defines methods for managing jailed environments
|
||||
|
@ -208,10 +190,10 @@ type JailManager interface {
|
|||
Call(chatID string, path string, args string) string
|
||||
|
||||
// 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
|
||||
JailCellVM(chatID string) (*otto.Otto, error)
|
||||
// GetJailCell returns instance of JailCell (which is persisted w/i jail cell) by chatID
|
||||
GetJailCell(chatID string) (JailCell, error)
|
||||
|
||||
// BaseJS allows to setup initial JavaScript to be loaded on each jail.Parse()
|
||||
BaseJS(js string)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -1,33 +1,48 @@
|
|||
package jail
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/status-im/status-go/geth/jail/console"
|
||||
"github.com/status-im/status-go/geth/node"
|
||||
)
|
||||
|
||||
// signals
|
||||
const (
|
||||
EventLocalStorageSet = "local_storage.set"
|
||||
EventSendMessage = "jail.send_message"
|
||||
EventSendMessage = "jail.send_message"
|
||||
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,
|
||||
// by adding and replacing method handlers.
|
||||
func registerHandlers(jail *Jail, vm *otto.Otto, chatID string) (err error) {
|
||||
jeth, err := vm.Get("jeth")
|
||||
func registerHandlers(jail *Jail, cell *JailCell, chatID string) error {
|
||||
jeth, err := cell.Get("jeth")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
if err = registerHandler("send", makeSendHandler(jail, chatID)); err != nil {
|
||||
if err = registerHandler("send", makeSendHandler(jail)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// register sendAsync handler
|
||||
if err = registerHandler("sendAsync", makeSendHandler(jail, chatID)); err != nil {
|
||||
if err = registerHandler("sendAsync", makeSendHandler(jail)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -37,27 +52,46 @@ func registerHandlers(jail *Jail, vm *otto.Otto, chatID string) (err error) {
|
|||
}
|
||||
|
||||
// define localStorage
|
||||
if err = vm.Set("localStorage", struct{}{}); err != nil {
|
||||
return
|
||||
if err = cell.Set("localStorage", struct{}{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// register localStorage.set handler
|
||||
localStorage, err := vm.Get("localStorage")
|
||||
localStorage, err := cell.Get("localStorage")
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// makeSendHandler returns jeth.send() and jeth.sendAsync() handler
|
||||
func makeSendHandler(jail *Jail, chatID string) func(call otto.FunctionCall) (response otto.Value) {
|
||||
return func(call otto.FunctionCall) (response otto.Value) {
|
||||
return jail.Send(chatID, call)
|
||||
}
|
||||
func makeSendHandler(jail *Jail) func(call otto.FunctionCall) (response otto.Value) {
|
||||
return jail.Send
|
||||
}
|
||||
|
||||
// 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 {
|
||||
client, err := jail.requestManager.RPCClient()
|
||||
if err != nil {
|
||||
return newErrorResponse(call, -32603, err.Error(), nil)
|
||||
return newErrorResponse(call.Otto, -32603, err.Error(), nil)
|
||||
}
|
||||
|
||||
var netListeningResult bool
|
||||
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 {
|
||||
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) {
|
||||
return func(call otto.FunctionCall) otto.Value {
|
||||
data := call.Argument(0).String()
|
||||
if len(data) > LocalStorageMaxDataLen { // cap input string
|
||||
data = data[:LocalStorageMaxDataLen]
|
||||
}
|
||||
|
||||
node.SendSignal(node.SignalEnvelope{
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,25 +5,17 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/eapache/go-resiliency/semaphore"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
"github.com/status-im/status-go/static"
|
||||
|
||||
"fknsrs.biz/p/ottoext/fetch"
|
||||
"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")
|
||||
|
||||
// errors
|
||||
|
@ -31,160 +23,101 @@ var (
|
|||
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.
|
||||
// Each cell is a separate JavaScript VM.
|
||||
type Jail struct {
|
||||
sync.RWMutex
|
||||
requestManager *RequestManager
|
||||
cells map[string]common.JailCell // jail supports running many isolated instances of jailed runtime
|
||||
baseJSCode string // JavaScript used to initialize all new cells with
|
||||
cells map[string]*JailCell // jail supports running many isolated instances of jailed runtime
|
||||
baseJSCode string // JavaScript used to initialize all new cells with
|
||||
}
|
||||
|
||||
// Copy returns a new JailCell instance with a new eventloop runtime associated with
|
||||
// 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
|
||||
// New returns new Jail environment.
|
||||
func New(nodeManager common.NodeManager) *Jail {
|
||||
return &Jail{
|
||||
cells: make(map[string]*JailCell),
|
||||
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) {
|
||||
jail.baseJSCode = js
|
||||
}
|
||||
|
||||
// NewJailCell initializes and returns jail cell
|
||||
func (jail *Jail) NewJailCell(id string) common.JailCell {
|
||||
// NewJailCell initializes and returns jail cell.
|
||||
func (jail *Jail) NewJailCell(id string) (common.JailCell, error) {
|
||||
if jail == nil {
|
||||
return nil, ErrInvalidJail
|
||||
}
|
||||
|
||||
vm := otto.New()
|
||||
|
||||
newJail, err := newJailCell(id, vm, loop.New(vm))
|
||||
if err != nil {
|
||||
//TODO(alex): Should we really panic here, his there
|
||||
// a better way. Think on it.
|
||||
panic(err)
|
||||
return nil, 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.
|
||||
// New context executes provided JavaScript code, right after the initialization.
|
||||
func (jail *Jail) Parse(chatID string, js string) string {
|
||||
var err error
|
||||
if jail == nil {
|
||||
return makeError(ErrInvalidJail.Error())
|
||||
}
|
||||
|
||||
jail.Lock()
|
||||
defer jail.Unlock()
|
||||
var err error
|
||||
var jcell *JailCell
|
||||
|
||||
jail.cells[chatID] = jail.NewJailCell(chatID)
|
||||
vm := jail.cells[chatID].CellVM()
|
||||
if jcell, err = jail.GetCell(chatID); err != nil {
|
||||
if _, mkerr := jail.NewJailCell(chatID); mkerr != nil {
|
||||
return makeError(mkerr.Error())
|
||||
}
|
||||
|
||||
initJjs := jail.baseJSCode + ";"
|
||||
if _, err = vm.Run(initJjs); err != nil {
|
||||
return makeError(err.Error())
|
||||
jcell, _ = jail.GetCell(chatID)
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
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())
|
||||
}
|
||||
|
||||
// sendMessage/showSuggestions handlers
|
||||
vm.Set("statusSignals", struct{}{})
|
||||
statusSignals, _ := vm.Get("statusSignals")
|
||||
jcell.Set("statusSignals", struct{}{})
|
||||
statusSignals, _ := jcell.Get("statusSignals")
|
||||
statusSignals.Object().Set("sendMessage", makeSendMessageHandler(chatID))
|
||||
statusSignals.Object().Set("showSuggestions", makeShowSuggestionsHandler(chatID))
|
||||
|
||||
|
@ -196,11 +129,11 @@ func (jail *Jail) Parse(chatID string, js string) string {
|
|||
return new Bignumber(val);
|
||||
}
|
||||
` + 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())
|
||||
}
|
||||
|
||||
res, err := vm.Get("catalog")
|
||||
res, err := jcell.Get("catalog")
|
||||
if err != nil {
|
||||
return makeError(err.Error())
|
||||
}
|
||||
|
@ -208,54 +141,34 @@ func (jail *Jail) Parse(chatID string, js string) string {
|
|||
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.
|
||||
func (jail *Jail) Call(chatID string, path string, args string) string {
|
||||
jail.RLock()
|
||||
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()
|
||||
jcell, err := jail.GetCell(chatID)
|
||||
if err != nil {
|
||||
return makeError(err.Error())
|
||||
}
|
||||
|
||||
// isolate VM to allow concurrent access
|
||||
vm := cellCopy.CellVM()
|
||||
res, err := vm.Call("call", nil, path, args)
|
||||
res, err := jcell.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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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()
|
||||
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.
|
||||
|
@ -290,7 +203,7 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
|
|||
txHash, err := jail.requestManager.ProcessSendTransactionRequest(call.Otto, req)
|
||||
resp.Set("result", txHash.Hex())
|
||||
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)
|
||||
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
|
||||
messageID, err := jail.requestManager.PreProcessRequest(call.Otto, req)
|
||||
if err != nil {
|
||||
return newErrorResponse(call, -32603, err.Error(), nil)
|
||||
return newErrorResponse(call.Otto, -32603, err.Error(), nil)
|
||||
}
|
||||
|
||||
errc := make(chan error, 1)
|
||||
|
@ -321,7 +234,7 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
|
|||
} else {
|
||||
resultVal, callErr := JSON.Call("parse", string(result))
|
||||
if callErr != nil {
|
||||
resp = newErrorResponse(call, -32603, callErr.Error(), &req.ID).Object()
|
||||
resp = newErrorResponse(call.Otto, -32603, callErr.Error(), &req.ID).Object()
|
||||
} else {
|
||||
resp.Set("result", resultVal)
|
||||
}
|
||||
|
@ -332,7 +245,7 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
|
|||
"message": err.Error(),
|
||||
})
|
||||
default:
|
||||
resp = newErrorResponse(call, -32603, err.Error(), &req.ID).Object()
|
||||
resp = newErrorResponse(call.Otto, -32603, err.Error(), &req.ID).Object()
|
||||
}
|
||||
resps.Call("push", resp)
|
||||
|
||||
|
@ -354,16 +267,16 @@ func (jail *Jail) Send(chatID string, call otto.FunctionCall) (response otto.Val
|
|||
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
|
||||
m := map[string]interface{}{"jsonrpc": "2.0", "id": id, "error": map[string]interface{}{"code": code, msg: msg}}
|
||||
res, _ := json.Marshal(m)
|
||||
val, _ := call.Otto.Run("(" + string(res) + ")")
|
||||
val, _ := otto.Run("(" + string(res) + ")")
|
||||
return val
|
||||
}
|
||||
|
||||
func newResultResponse(call otto.FunctionCall, result interface{}) otto.Value {
|
||||
resp, _ := call.Otto.Object(`({"jsonrpc":"2.0"})`)
|
||||
func newResultResponse(vm *otto.Otto, result interface{}) otto.Value {
|
||||
resp, _ := vm.Object(`({"jsonrpc":"2.0"})`)
|
||||
resp.Set("result", result) // nolint: errcheck
|
||||
|
||||
return resp.Value()
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -3,12 +3,9 @@ package jail_test
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/status-im/status-go/geth/jail"
|
||||
"github.com/status-im/status-go/geth/node"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
|
@ -50,9 +47,9 @@ func (s *JailTestSuite) TestInit() {
|
|||
}
|
||||
|
||||
// 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.Nil(vm)
|
||||
require.Nil(cell)
|
||||
|
||||
// create VM (w/o properly initializing base JS script)
|
||||
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}`))
|
||||
|
||||
// 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.NotNil(vm)
|
||||
require.NotNil(cell)
|
||||
|
||||
statusJS := baseStatusJSCode + `;
|
||||
_status_catalog.commands["testCommand"] = function (params) {
|
||||
|
@ -109,7 +106,7 @@ func (s *JailTestSuite) TestFunctionCall() {
|
|||
|
||||
// call with wrong chat id
|
||||
response := s.jail.Call("chatIDNonExistent", "", "")
|
||||
expectedError := `{"error":"Cell[chatIDNonExistent] doesn't exist."}`
|
||||
expectedError := `{"error":"cell[chatIDNonExistent] doesn't exist"}`
|
||||
require.Equal(expectedError, response)
|
||||
|
||||
// call extraFunc()
|
||||
|
@ -118,83 +115,6 @@ func (s *JailTestSuite) TestFunctionCall() {
|
|||
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() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.jail)
|
||||
|
@ -207,19 +127,19 @@ func (s *JailTestSuite) TestJailRPCSend() {
|
|||
s.jail.Parse(testChatID, ``)
|
||||
|
||||
// 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.NotNil(vm)
|
||||
require.NotNil(cell)
|
||||
|
||||
// internally (since we replaced `web3.send` with `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 sendResult = web3.fromWei(balance, "ether")
|
||||
`)
|
||||
require.NoError(err)
|
||||
|
||||
value, err := vm.Get("sendResult")
|
||||
value, err := cell.Get("sendResult")
|
||||
require.NoError(err, "cannot obtain result of balance check operation")
|
||||
|
||||
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)")
|
||||
}
|
||||
|
||||
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() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.jail)
|
||||
|
||||
// TODO(tiabc): Is this required?
|
||||
s.StartTestNode(params.RopstenNetworkID)
|
||||
defer s.StopTestNode()
|
||||
|
||||
s.jail.Parse(testChatID, "")
|
||||
|
||||
// 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)
|
||||
|
||||
_, err = vm.Run(`
|
||||
_, err = cell.Run(`
|
||||
var responseValue = web3.isConnected();
|
||||
responseValue = JSON.stringify(responseValue);
|
||||
`)
|
||||
require.NoError(err)
|
||||
|
||||
responseValue, err := vm.Get("responseValue")
|
||||
responseValue, err := cell.Get("responseValue")
|
||||
require.NoError(err, "cannot obtain result of isConnected()")
|
||||
|
||||
response, err := responseValue.ToString()
|
||||
|
@ -278,7 +186,7 @@ func (s *JailTestSuite) TestLocalStorageSet() {
|
|||
s.jail.Parse(testChatID, "")
|
||||
|
||||
// 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)
|
||||
|
||||
testData := "foobar"
|
||||
|
@ -306,7 +214,7 @@ func (s *JailTestSuite) TestLocalStorageSet() {
|
|||
}
|
||||
})
|
||||
|
||||
_, err = vm.Run(`
|
||||
_, err = cell.Run(`
|
||||
var responseValue = localStorage.set("` + testData + `");
|
||||
responseValue = JSON.stringify(responseValue);
|
||||
`)
|
||||
|
@ -320,7 +228,7 @@ func (s *JailTestSuite) TestLocalStorageSet() {
|
|||
s.Fail("operation timed out")
|
||||
}
|
||||
|
||||
responseValue, err := vm.Get("responseValue")
|
||||
responseValue, err := cell.Get("responseValue")
|
||||
s.NoError(err, "cannot obtain result of localStorage.set()")
|
||||
|
||||
response, err := responseValue.ToString()
|
||||
|
|
|
@ -23,6 +23,7 @@ type RequestManager struct {
|
|||
nodeManager common.NodeManager
|
||||
}
|
||||
|
||||
// NewRequestManager returns a new instance of the RequestManager pointer.
|
||||
func NewRequestManager(nodeManager common.NodeManager) *RequestManager {
|
||||
return &RequestManager{
|
||||
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
|
||||
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 {
|
||||
vm.Call("addContext", nil, messageID, common.MessageIDKey, messageID) // nolint: errcheck
|
||||
}
|
||||
|
|
|
@ -241,11 +241,7 @@ func (m *NodeManager) populateStaticPeers() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
enodes, err := m.config.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
log.Warn("Can not load boot nodes", "error", err)
|
||||
}
|
||||
for _, enode := range enodes {
|
||||
for _, enode := range m.config.BootClusterConfig.BootNodes {
|
||||
err := m.addPeer(enode)
|
||||
if err != nil {
|
||||
log.Warn("Boot node addition failed", "error", err)
|
||||
|
|
|
@ -4,13 +4,10 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
@ -74,17 +71,6 @@ func MakeNode(config *params.NodeConfig) (*node.Node, error) {
|
|||
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)
|
||||
if err != nil {
|
||||
return nil, ErrNodeMakeFailure
|
||||
|
@ -142,90 +128,24 @@ func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config {
|
|||
|
||||
// updateCHT changes trusted canonical hash trie root
|
||||
func updateCHT(eth *les.LightEthereum, config *params.NodeConfig) {
|
||||
bc := eth.BlockChain()
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
if !config.BootClusterConfig.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
// resort to manually updated
|
||||
log.Info("Loading CHT from net failed, setting manually")
|
||||
if bc.Genesis().Hash() == params.MainNetGenesisHash {
|
||||
eth.WriteTrustedCht(light.TrustedCht{
|
||||
Number: 805,
|
||||
Root: gethcommon.HexToHash("85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f"),
|
||||
})
|
||||
log.Info("Added trusted CHT for mainnet")
|
||||
if config.BootClusterConfig.RootNumber == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if bc.Genesis().Hash() == params.RopstenNetGenesisHash {
|
||||
root := "fa851b5252cc48ab55f375833b0344cc5c7cacea69be7e2a57976c38d3bb3aef"
|
||||
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 config.BootClusterConfig.RootHash == "" {
|
||||
return
|
||||
}
|
||||
|
||||
//if bc.Genesis().Hash() == params.RinkebyNetGenesisHash {
|
||||
// root := "0xb100882d00a09292f15e712707649b24d019a47a509e83a00530ac542425c3bd"
|
||||
// if config.DevMode {
|
||||
// root = "0xb100882d00a09292f15e712707649b24d019a47a509e83a00530ac542425c3bd"
|
||||
// }
|
||||
// eth.WriteTrustedCht(light.TrustedCht{
|
||||
// Number: 55,
|
||||
// Root: gethcommon.HexToHash(root),
|
||||
// })
|
||||
// log.Info("Added trusted CHT for Rinkeby", "CHT", root)
|
||||
//}
|
||||
eth.WriteTrustedCht(light.TrustedCht{
|
||||
Number: uint64(config.BootClusterConfig.RootNumber),
|
||||
Root: gethcommon.HexToHash(config.BootClusterConfig.RootHash),
|
||||
})
|
||||
log.Info("Added trusted CHT",
|
||||
"develop", config.DevMode, "number", config.BootClusterConfig.RootNumber, "hash", config.BootClusterConfig.RootHash)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
whisperConfig := config.WhisperConfig
|
||||
whisperService := whisper.New()
|
||||
whisperService := whisper.New(nil)
|
||||
|
||||
// enable mail service
|
||||
if whisperConfig.MailServerNode {
|
||||
|
|
|
@ -7,14 +7,16 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/status-im/status-go/static"
|
||||
)
|
||||
|
||||
// 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 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
|
||||
type FirebaseConfig struct {
|
||||
// AuthorizationKeyFile file path that contains FCM authorization key
|
||||
|
@ -89,8 +85,6 @@ func (c *FirebaseConfig) ReadAuthorizationKeyFile() ([]byte, error) {
|
|||
return key, nil
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
|
||||
// WhisperConfig holds SHH-related configuration
|
||||
type WhisperConfig struct {
|
||||
// Enabled flag specifies whether protocol is enabled
|
||||
|
@ -177,8 +171,6 @@ func (c *WhisperConfig) String() string {
|
|||
return string(data)
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
|
||||
// SwarmConfig holds Swarm-related configuration
|
||||
type SwarmConfig struct {
|
||||
// Enabled flag specifies whether protocol is enabled
|
||||
|
@ -191,8 +183,6 @@ func (c *SwarmConfig) String() string {
|
|||
return string(data)
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
|
||||
// BootClusterConfig holds configuration for supporting boot cluster, which is a temporary
|
||||
// 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).
|
||||
|
@ -200,12 +190,15 @@ type BootClusterConfig struct {
|
|||
// Enabled flag specifies whether feature is enabled
|
||||
Enabled bool
|
||||
|
||||
// ConfigFile is a path to JSON file containing array of boot nodes
|
||||
// See `static/bootcluster/*.json` for cluster configurations provided
|
||||
// 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
|
||||
// `static/bootcluster` folder.
|
||||
ConfigFile string
|
||||
// RootNumber CHT root number
|
||||
RootNumber int
|
||||
|
||||
// RootHash is hash of CHT root for a given root number
|
||||
RootHash 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
|
||||
|
@ -214,8 +207,6 @@ func (c *BootClusterConfig) String() string {
|
|||
return string(data)
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
|
||||
// NodeConfig stores configuration options for a node
|
||||
type NodeConfig struct {
|
||||
// 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,
|
||||
HTTPHost: HTTPHost,
|
||||
HTTPPort: HTTPPort,
|
||||
APIModules: APIModules,
|
||||
WSHost: WSHost,
|
||||
WSPort: WSPort,
|
||||
MaxPeers: MaxPeers,
|
||||
|
@ -328,14 +320,13 @@ func NewNodeConfig(dataDir string, networkID uint64, devMode bool) (*NodeConfig,
|
|||
LogFile: LogFile,
|
||||
LogLevel: LogLevel,
|
||||
LogToStderr: LogToStderr,
|
||||
LightEthConfig: &LightEthConfig{
|
||||
Enabled: true,
|
||||
DatabaseCache: DatabaseCache,
|
||||
CHTRootConfigURL: CHTRootConfigURL,
|
||||
},
|
||||
BootClusterConfig: &BootClusterConfig{
|
||||
Enabled: true,
|
||||
ConfigFile: BootClusterConfigFile,
|
||||
Enabled: true,
|
||||
BootNodes: []string{},
|
||||
},
|
||||
LightEthConfig: &LightEthConfig{
|
||||
Enabled: true,
|
||||
DatabaseCache: DatabaseCache,
|
||||
},
|
||||
WhisperConfig: &WhisperConfig{
|
||||
Enabled: true,
|
||||
|
@ -408,41 +399,12 @@ func (c *NodeConfig) Save() error {
|
|||
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
|
||||
// (we have a development/production and mobile/full node dependent configurations)
|
||||
func (c *NodeConfig) updateConfig() error {
|
||||
if err := c.updateGenesisConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.updateRPCConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.updateBootClusterConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -478,36 +440,55 @@ func (c *NodeConfig) updateGenesisConfig() error {
|
|||
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 {
|
||||
var configFile string
|
||||
|
||||
switch c.NetworkID {
|
||||
case MainNetworkID:
|
||||
configFile = "homestead.prod.json"
|
||||
case RopstenNetworkID:
|
||||
configFile = "ropsten.prod.json"
|
||||
case RinkebyNetworkID:
|
||||
configFile = "rinkeby.prod.json"
|
||||
if !c.BootClusterConfig.Enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.DevMode {
|
||||
configFile = strings.Replace(configFile, "prod", "dev", 1)
|
||||
// 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 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 {
|
||||
c.BootClusterConfig.ConfigFile = configFile
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
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
|
||||
}
|
||||
|
||||
// updateRPCConfig transforms RPC settings to meet requirements of a given configuration
|
||||
func (c *NodeConfig) updateRPCConfig() error {
|
||||
c.APIModules = ProdAPIModules
|
||||
|
||||
if c.DevMode {
|
||||
c.APIModules = DevAPIModules
|
||||
for _, cluster := range clusters {
|
||||
if cluster.NetworkID == int(c.NetworkID) {
|
||||
c.BootClusterConfig.RootNumber = cluster.Prod.Number
|
||||
c.BootClusterConfig.RootHash = cluster.Prod.Hash
|
||||
c.BootClusterConfig.BootNodes = cluster.Prod.BootNodes
|
||||
if c.DevMode {
|
||||
c.BootClusterConfig.RootNumber = cluster.Dev.Number
|
||||
c.BootClusterConfig.RootHash = cluster.Dev.Hash
|
||||
c.BootClusterConfig.BootNodes = cluster.Dev.BootNodes
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -13,6 +12,7 @@ import (
|
|||
gethparams "github.com/ethereum/go-ethereum/params"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
. "github.com/status-im/status-go/geth/testing"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var loadConfigTestCases = []struct {
|
||||
|
@ -35,9 +35,7 @@ var loadConfigTestCases = []struct {
|
|||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err == nil {
|
||||
t.Fatal("error is expected, not thrown")
|
||||
}
|
||||
require.Error(t, err, "error is expected, not thrown")
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -47,9 +45,7 @@ var loadConfigTestCases = []struct {
|
|||
"Name": "TestStatusNode"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != params.ErrMissingDataDir {
|
||||
t.Fatalf("expected error not thrown, expected: %v, thrown: %v", params.ErrMissingDataDir, err)
|
||||
}
|
||||
require.Equal(t, params.ErrMissingDataDir, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -58,9 +54,7 @@ var loadConfigTestCases = []struct {
|
|||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != params.ErrMissingNetworkID {
|
||||
t.Fatalf("expected error not thrown, expected: %v, thrown: %v", params.ErrMissingNetworkID, err)
|
||||
}
|
||||
require.Equal(t, params.ErrMissingNetworkID, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -70,13 +64,8 @@ var loadConfigTestCases = []struct {
|
|||
"DataDir": "/storage/emulated/0/ethereum/"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectedDataDir := "/storage/emulated/0/ethereum/"
|
||||
if nodeConfig.DataDir != expectedDataDir {
|
||||
t.Fatalf("incorrect DataDir used, expected: %v, got: %v", expectedDataDir, nodeConfig.DataDir)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "/storage/emulated/0/ethereum/", nodeConfig.DataDir)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -86,22 +75,13 @@ var loadConfigTestCases = []struct {
|
|||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(dataDir); os.IsNotExist(err) {
|
||||
t.Fatalf("data directory doesn't exist: %s", dataDir)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedDataDir := dataDir
|
||||
if nodeConfig.DataDir != expectedDataDir {
|
||||
t.Fatalf("incorrect DataDir used, expected: %v, got: %v", expectedDataDir, nodeConfig.DataDir)
|
||||
}
|
||||
_, err = os.Stat(dataDir)
|
||||
require.False(t, os.IsNotExist(err), "data directory doesn't exist")
|
||||
require.Equal(t, dataDir, nodeConfig.DataDir)
|
||||
|
||||
expectedKeyStoreDir := filepath.Join(dataDir, params.KeyStoreDir)
|
||||
if nodeConfig.KeyStoreDir != expectedKeyStoreDir {
|
||||
t.Fatalf("incorrect KeyStoreDir used, expected: %v, got: %v", expectedKeyStoreDir, nodeConfig.KeyStoreDir)
|
||||
}
|
||||
require.Equal(t, filepath.Join(dataDir, params.KeyStoreDir), filepath.Join(dataDir, params.KeyStoreDir))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -112,18 +92,9 @@ var loadConfigTestCases = []struct {
|
|||
"KeyStoreDir": "/foo/bar"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
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)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, dataDir, nodeConfig.DataDir)
|
||||
require.Equal(t, "/foo/bar", nodeConfig.KeyStoreDir)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -141,44 +112,17 @@ var loadConfigTestCases = []struct {
|
|||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
if nodeConfig.NetworkID != 3 {
|
||||
t.Fatal("wrong NetworkId")
|
||||
}
|
||||
|
||||
if nodeConfig.Name != "TestStatusNode" {
|
||||
t.Fatal("wrong Name")
|
||||
}
|
||||
|
||||
if nodeConfig.HTTPPort != params.HTTPPort {
|
||||
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")
|
||||
}
|
||||
require.EqualValues(t, 3, nodeConfig.NetworkID)
|
||||
require.Equal(t, "TestStatusNode", nodeConfig.Name)
|
||||
require.Equal(t, params.HTTPPort, nodeConfig.HTTPPort)
|
||||
require.Equal(t, params.HTTPHost, nodeConfig.HTTPHost)
|
||||
require.True(t, nodeConfig.RPCEnabled)
|
||||
require.False(t, nodeConfig.WSEnabled)
|
||||
require.Equal(t, 4242, nodeConfig.WSPort)
|
||||
require.True(t, nodeConfig.IPCEnabled)
|
||||
require.Equal(t, 64, nodeConfig.LightEthConfig.DatabaseCache)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -195,41 +139,25 @@ var loadConfigTestCases = []struct {
|
|||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
genesis := new(core.Genesis)
|
||||
if err := json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis)
|
||||
require.NoError(t, err)
|
||||
|
||||
chainConfig := genesis.Config
|
||||
refChainConfig := gethparams.TestnetChainConfig
|
||||
|
||||
if chainConfig.HomesteadBlock.Cmp(refChainConfig.HomesteadBlock) != 0 {
|
||||
t.Fatal("invalid chainConfig.HomesteadBlock")
|
||||
}
|
||||
if chainConfig.DAOForkBlock != nil { // already forked
|
||||
t.Fatal("invalid chainConfig.DAOForkBlock")
|
||||
}
|
||||
if chainConfig.DAOForkSupport != refChainConfig.DAOForkSupport {
|
||||
t.Fatal("invalid chainConfig.DAOForkSupport")
|
||||
}
|
||||
if chainConfig.EIP150Block.Cmp(refChainConfig.EIP150Block) != 0 {
|
||||
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")
|
||||
}
|
||||
require.Empty(t, chainConfig.HomesteadBlock.Cmp(refChainConfig.HomesteadBlock), "invalid chainConfig.HomesteadBlock")
|
||||
require.Nil(t, chainConfig.DAOForkBlock)
|
||||
require.Equal(t, refChainConfig.DAOForkSupport, chainConfig.DAOForkSupport)
|
||||
|
||||
require.Empty(t, chainConfig.EIP150Block.Cmp(refChainConfig.EIP150Block))
|
||||
require.Equal(t, refChainConfig.EIP150Hash, chainConfig.EIP150Hash)
|
||||
|
||||
require.Empty(t, chainConfig.EIP155Block.Cmp(refChainConfig.EIP155Block))
|
||||
require.Empty(t, chainConfig.EIP158Block.Cmp(refChainConfig.EIP158Block))
|
||||
require.Empty(t, chainConfig.ChainId.Cmp(refChainConfig.ChainId))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -246,39 +174,22 @@ var loadConfigTestCases = []struct {
|
|||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
genesis := new(core.Genesis)
|
||||
if err := json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = json.Unmarshal([]byte(nodeConfig.LightEthConfig.Genesis), genesis)
|
||||
require.NoError(t, err)
|
||||
|
||||
chainConfig := genesis.Config
|
||||
if chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock) != 0 {
|
||||
t.Fatal("invalid chainConfig.HomesteadBlock")
|
||||
}
|
||||
if chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock) != 0 {
|
||||
t.Fatal("invalid chainConfig.DAOForkBlock")
|
||||
}
|
||||
if !chainConfig.DAOForkSupport {
|
||||
t.Fatal("invalid chainConfig.DAOForkSupport")
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
require.Empty(t, chainConfig.HomesteadBlock.Cmp(gethparams.MainNetHomesteadBlock))
|
||||
require.Empty(t, chainConfig.DAOForkBlock.Cmp(gethparams.MainNetDAOForkBlock))
|
||||
require.True(t, chainConfig.DAOForkSupport)
|
||||
require.Empty(t, chainConfig.EIP150Block.Cmp(gethparams.MainNetHomesteadGasRepriceBlock))
|
||||
require.Equal(t, gethparams.MainNetHomesteadGasRepriceHash, chainConfig.EIP150Hash)
|
||||
require.Empty(t, chainConfig.EIP155Block.Cmp(gethparams.MainNetSpuriousDragon))
|
||||
require.Empty(t, chainConfig.EIP158Block.Cmp(gethparams.MainNetSpuriousDragon))
|
||||
require.Empty(t, chainConfig.ChainId.Cmp(gethparams.MainNetChainID))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -292,14 +203,8 @@ var loadConfigTestCases = []struct {
|
|||
"WSEnabled": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
networkId := uint64(311)
|
||||
if nodeConfig.NetworkID != networkId {
|
||||
t.Fatalf("unexpected NetworkID, expected: %v, got: %v", networkId, nodeConfig.NetworkID)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 311, nodeConfig.NetworkID)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -309,36 +214,32 @@ var loadConfigTestCases = []struct {
|
|||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
// Bootnodes for dev and prod modes are the same so no need for a separate Ropsten Prod test.
|
||||
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != params.BootClusterConfigFile {
|
||||
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
|
||||
params.BootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
require.NoError(t, 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)
|
||||
|
||||
if !nodeConfig.BootClusterConfig.Enabled {
|
||||
t.Fatal("boot cluster is expected to be enabled by default")
|
||||
}
|
||||
|
||||
enodes, err := nodeConfig.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
enodes := nodeConfig.BootClusterConfig.BootNodes
|
||||
expectedEnodes := []string{
|
||||
"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",
|
||||
}
|
||||
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)
|
||||
"enode://7ab298cedc4185a894d21d8a4615262ec6bdce66c9b6783878258e0d5b31013d30c9038932432f70e5b2b6a5cd323bf820554fcb22fbc7b45367889522e9c449@51.15.63.93:30303",
|
||||
"enode://f59e8701f18c79c5cbc7618dc7bb928d44dc2f5405c7d693dad97da2d8585975942ec6fd36d3fe608bfdc7270a34a4dd00f38cfe96b2baa24f7cd0ac28d382a1@51.15.79.88:30303",
|
||||
"enode://e2a3587b7b41acfc49eddea9229281905d252efba0baf565cf6276df17faf04801b7879eead757da8b5be13b05f25e775ab6d857ff264bc53a89c027a657dd10@51.15.45.114:30303",
|
||||
"enode://fe991752c4ceab8b90608fbf16d89a5f7d6d1825647d4981569ebcece1b243b2000420a5db721e214231c7a6da3543fa821185c706cbd9b9be651494ec97f56a@51.15.67.119:30303",
|
||||
"enode://482484b9198530ee2e00db89791823244ca41dcd372242e2e1297dd06f6d8dd357603960c5ad9cc8dc15fcdf0e4edd06b7ad7db590e67a0b54f798c26581ebd7@51.15.75.138:30303",
|
||||
"enode://9e99e183b5c71d51deb16e6b42ac9c26c75cfc95fff9dfae828b871b348354cbecf196dff4dd43567b26c8241b2b979cb4ea9f8dae2d9aacf86649dafe19a39a@51.15.79.176:30303",
|
||||
"enode://12d52c3796700fb5acff2c7d96df7bbb6d7109b67f3442ee3d99ac1c197016cddb4c3568bbeba05d39145c59c990cd64f76bc9b00d4b13f10095c49507dd4cf9@51.15.63.110:30303",
|
||||
"enode://0f7c65277f916ff4379fe520b875082a56e587eb3ce1c1567d9ff94206bdb05ba167c52272f20f634cd1ebdec5d9dfeb393018bfde1595d8e64a717c8b46692f@51.15.54.150:30303",
|
||||
"enode://e006f0b2dc98e757468b67173295519e9b6d5ff4842772acb18fd055c620727ab23766c95b8ee1008dea9e8ef61e83b1515ddb3fb56dbfb9dbf1f463552a7c9f@212.47.237.127:30303",
|
||||
"enode://d40871fc3e11b2649700978e06acd68a24af54e603d4333faecb70926ca7df93baa0b7bf4e927fcad9a7c1c07f9b325b22f6d1730e728314d0e4e6523e5cebc2@51.15.132.235:30303",
|
||||
"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) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled {
|
||||
t.Fatal("boot cluster is expected to be disabled")
|
||||
}
|
||||
require.NoError(t, 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)
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Ropsten Prod)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"NetworkId": 3,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "ropsten.prod.json"
|
||||
}
|
||||
"DevMode": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, 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"
|
||||
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)
|
||||
}
|
||||
enodes := nodeConfig.BootClusterConfig.BootNodes
|
||||
expectedEnodes := []string{
|
||||
"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",
|
||||
}
|
||||
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)
|
||||
"enode://7ab298cedc4185a894d21d8a4615262ec6bdce66c9b6783878258e0d5b31013d30c9038932432f70e5b2b6a5cd323bf820554fcb22fbc7b45367889522e9c449@51.15.63.93:30303",
|
||||
"enode://f59e8701f18c79c5cbc7618dc7bb928d44dc2f5405c7d693dad97da2d8585975942ec6fd36d3fe608bfdc7270a34a4dd00f38cfe96b2baa24f7cd0ac28d382a1@51.15.79.88:30303",
|
||||
"enode://e2a3587b7b41acfc49eddea9229281905d252efba0baf565cf6276df17faf04801b7879eead757da8b5be13b05f25e775ab6d857ff264bc53a89c027a657dd10@51.15.45.114:30303",
|
||||
"enode://fe991752c4ceab8b90608fbf16d89a5f7d6d1825647d4981569ebcece1b243b2000420a5db721e214231c7a6da3543fa821185c706cbd9b9be651494ec97f56a@51.15.67.119:30303",
|
||||
"enode://482484b9198530ee2e00db89791823244ca41dcd372242e2e1297dd06f6d8dd357603960c5ad9cc8dc15fcdf0e4edd06b7ad7db590e67a0b54f798c26581ebd7@51.15.75.138:30303",
|
||||
"enode://9e99e183b5c71d51deb16e6b42ac9c26c75cfc95fff9dfae828b871b348354cbecf196dff4dd43567b26c8241b2b979cb4ea9f8dae2d9aacf86649dafe19a39a@51.15.79.176:30303",
|
||||
"enode://12d52c3796700fb5acff2c7d96df7bbb6d7109b67f3442ee3d99ac1c197016cddb4c3568bbeba05d39145c59c990cd64f76bc9b00d4b13f10095c49507dd4cf9@51.15.63.110:30303",
|
||||
"enode://0f7c65277f916ff4379fe520b875082a56e587eb3ce1c1567d9ff94206bdb05ba167c52272f20f634cd1ebdec5d9dfeb393018bfde1595d8e64a717c8b46692f@51.15.54.150:30303",
|
||||
"enode://e006f0b2dc98e757468b67173295519e9b6d5ff4842772acb18fd055c620727ab23766c95b8ee1008dea9e8ef61e83b1515ddb3fb56dbfb9dbf1f463552a7c9f@212.47.237.127:30303",
|
||||
"enode://d40871fc3e11b2649700978e06acd68a24af54e603d4333faecb70926ca7df93baa0b7bf4e927fcad9a7c1c07f9b325b22f6d1730e728314d0e4e6523e5cebc2@51.15.132.235:30303",
|
||||
"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)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "rinkeby.dev.json"
|
||||
}
|
||||
"NetworkId": 4,
|
||||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, 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"
|
||||
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)
|
||||
}
|
||||
enodes := nodeConfig.BootClusterConfig.BootNodes
|
||||
expectedEnodes := []string{
|
||||
"enode://7512c8f6e7ffdcc723cf77e602a1de9d8cc2e8ad35db309464819122cd773857131aee390fec33894db13da730c8432bb248eed64039e3810e156e979b2847cb@51.15.78.243:30303",
|
||||
"enode://1cc27a5a41130a5c8b90db5b2273dc28f7b56f3edfc0dcc57b665d451274b26541e8de49ea7a074281906a82209b9600239c981163b6ff85c3038a8e2bc5d8b8@51.15.68.93:30303",
|
||||
"enode://798d17064141b8f88df718028a8272b943d1cb8e696b3dab56519c70b77b1d3469b56b6f4ce3788457646808f5c7299e9116626f2281f30b959527b969a71e4f@51.15.75.244:30303",
|
||||
}
|
||||
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)
|
||||
}
|
||||
require.Equal(t, expectedEnodes, enodes)
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Rinkeby Prod)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"NetworkId": 4,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "rinkeby.prod.json"
|
||||
}
|
||||
"DevMode": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, 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"
|
||||
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)
|
||||
}
|
||||
enodes := nodeConfig.BootClusterConfig.BootNodes
|
||||
expectedEnodes := []string{
|
||||
"enode://fda3f6273a0f2da4ac5858d1f52e5afaf9def281121be3d37558c67d4d9ca26c6ad7a0520b2cd7454120fb770e86d5760487c9924b2166e65485f606e56d60fc@51.15.69.144:30303",
|
||||
"enode://ba41aa829287a0a9076d9bffed97c8ce2e491b99873288c9e886f16fd575306ac6c656db4fbf814f5a9021aec004ffa9c0ae8650f92fd10c12eeb7c364593eb3@51.15.69.147:30303",
|
||||
"enode://28ecf5272b560ca951f4cd7f1eb8bd62da5853b026b46db432c4b01797f5b0114819a090a72acd7f32685365ecd8e00450074fa0673039aefe10f3fb666e0f3f@51.15.76.249:30303",
|
||||
}
|
||||
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)
|
||||
}
|
||||
require.Equal(t, expectedEnodes, enodes)
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Homestead Dev)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "homestead.dev.json"
|
||||
}
|
||||
"NetworkId": 1,
|
||||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, 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"
|
||||
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)
|
||||
}
|
||||
enodes := nodeConfig.BootClusterConfig.BootNodes
|
||||
expectedEnodes := []string{
|
||||
"enode://93833be81c3d1bdb2ae5cde258c8f82ad1011a1bea8eb49fe50b0af394d4f7f7e45974356870552f36744efd732692a64865d1e8b64114eaf89a1bad0a1903a2@51.15.64.29:30303",
|
||||
"enode://d76854bc54144b2269c5316d5f00f0a194efee2fb8d31e7b1939effd7e17f25773f8dc7fda8c4eb469450799da7f39b4e364e2a278d91b53539dcbb10b139635@51.15.73.37:30303",
|
||||
"enode://57874205931df976079e4ff8ebb5756461030fb00f73486bd5ec4ae6ed6ba98e27d09f58e59bd85281d24084a6062bc8ab514dbcdaa9678fc3001d47772e626e@51.15.75.213:30303",
|
||||
}
|
||||
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)
|
||||
}
|
||||
require.Equal(t, expectedEnodes, enodes)
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Homestead Prod)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"NetworkId": 1,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "homestead.prod.json"
|
||||
}
|
||||
"DevMode": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, 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"
|
||||
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)
|
||||
}
|
||||
enodes := nodeConfig.BootClusterConfig.BootNodes
|
||||
expectedEnodes := []string{
|
||||
"enode://f3b0e5dca730962bae814f3402b8f8a296644c33e8d7a95bd1ab313143a752c77076a03bcb76263570f2f34d4eb530f1daf5054c0990921a872a34eb505dcedf@51.15.73.129:30303",
|
||||
"enode://fce0d1c2292829b0eccce444f8943f88087ce00a5e910b157972ee1658a948d23c7a046f26567f73b2b18d126811509d7ef1de5be9b1decfcbb14738a590c477@51.15.75.187:30303",
|
||||
"enode://3b4b9fa02ae8d54c2db51a674bc93d85649b4775f22400f74ae25e9f1c665baa3bcdd33cadd2c1a93cd08a6af984cb605fbb61ec0d750a11d48d4080298af008@51.15.77.193:30303",
|
||||
}
|
||||
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)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`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)
|
||||
}
|
||||
require.Equal(t, expectedEnodes, enodes)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -590,22 +385,9 @@ var loadConfigTestCases = []struct {
|
|||
"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")
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != params.BootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
params.BootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.True(t, nodeConfig.DevMode)
|
||||
require.True(t, nodeConfig.BootClusterConfig.Enabled)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -616,183 +398,9 @@ var loadConfigTestCases = []struct {
|
|||
"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 (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)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.False(t, nodeConfig.DevMode)
|
||||
require.True(t, nodeConfig.BootClusterConfig.Enabled)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -806,9 +414,8 @@ func TestLoadNodeConfig(t *testing.T) {
|
|||
|
||||
// create sample Bootstrap Cluster Config
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(tmpDir, "bootstrap-cluster.json"), bootstrapConfig, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
t.Log(tmpDir)
|
||||
|
||||
for _, testCase := range loadConfigTestCases {
|
||||
|
@ -822,32 +429,24 @@ func TestLoadNodeConfig(t *testing.T) {
|
|||
func TestConfigWriteRead(t *testing.T) {
|
||||
configReadWrite := func(networkId uint64, refFile string) {
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "geth-config-tests")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
||||
|
||||
nodeConfig, err := params.NewNodeConfig(tmpDir, networkId, true)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot create new config object: %v", err)
|
||||
}
|
||||
require.Nil(t, err, "cannot create new config object")
|
||||
|
||||
if err := nodeConfig.Save(); err != nil {
|
||||
t.Fatalf("cannot persist configuration: %v", err)
|
||||
}
|
||||
err = nodeConfig.Save()
|
||||
require.Nil(t, err, "cannot persist configuration")
|
||||
|
||||
loadedConfigData, err := ioutil.ReadFile(filepath.Join(nodeConfig.DataDir, "config.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("cannot read configuration from disk: %v", err)
|
||||
}
|
||||
require.Nil(t, err, "cannot read configuration from disk")
|
||||
|
||||
refConfigData := LoadFromFile(refFile)
|
||||
|
||||
refConfigData = strings.Replace(refConfigData, "$TMPDIR", nodeConfig.DataDir, -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")
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package params
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
const (
|
||||
// ClientIdentifier is client identifier to advertise over the network
|
||||
ClientIdentifier = "StatusIM"
|
||||
|
@ -27,11 +23,8 @@ const (
|
|||
// HTTPPort is HTTP-RPC port (replaced in unit tests)
|
||||
HTTPPort = 8545
|
||||
|
||||
// DevAPIModules is a list of modules to expose via any type of RPC (HTTP, IPC) during development
|
||||
DevAPIModules = "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"
|
||||
// APIModules is a list of modules to expose via any type of RPC (HTTP, IPC, in-proc)
|
||||
APIModules = "db,eth,net,web3,shh,personal,admin"
|
||||
|
||||
// WSHost is a host interface for the websocket RPC server
|
||||
WSHost = "localhost"
|
||||
|
@ -57,7 +50,11 @@ const (
|
|||
|
||||
// CHTRootConfigURL defines URL to file containing hard-coded CHT roots
|
||||
// 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 = "geth.log"
|
||||
|
@ -95,13 +92,4 @@ const (
|
|||
|
||||
// RinkebyNetworkID is id of a test network (on PoA)
|
||||
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
|
@ -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"
|
||||
]
|
|
@ -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"
|
||||
]
|
|
@ -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"
|
||||
]
|
|
@ -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"
|
||||
]
|
|
@ -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"
|
||||
]
|
|
@ -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"
|
||||
]
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"Node": {
|
||||
"SyncSeconds": 7,
|
||||
"SyncSeconds": 30,
|
||||
"HTTPPort": 8645,
|
||||
"WSPort": 8646
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Package static embeds static (JS, HTML) resources right into the binaries
|
||||
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/...
|
||||
|
|
|
@ -286,7 +286,7 @@ describe('Whisper Tests', function () {
|
|||
}, 200);
|
||||
});
|
||||
|
||||
it('shh.unsubscribe(filterID)', function () {
|
||||
it.skip('shh.unsubscribe(filterID)', function () {
|
||||
node1.shh.unsubscribe(filterid1);
|
||||
node1.shh.unsubscribe(filterid2);
|
||||
});
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
.git
|
||||
**/.git
|
||||
**/*_test.go
|
||||
|
||||
build/_workspace
|
||||
build/_bin
|
||||
tests/testdata
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
|
@ -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.
|
|
@ -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]
|
||||
````
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "tests"]
|
||||
path = tests/testdata
|
||||
url = https://github.com/ethereum/tests
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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"]
|
|
@ -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
|
|
@ -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.
|
|
@ -0,0 +1 @@
|
|||
1.6.7
|
|
@ -17,11 +17,9 @@
|
|||
package abi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
|
@ -67,7 +65,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
|
|||
}
|
||||
method = m
|
||||
}
|
||||
arguments, err := method.pack(method, args...)
|
||||
arguments, err := method.pack(args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -78,199 +76,6 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
|
|||
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
|
||||
// assignment.
|
||||
var (
|
||||
|
|
|
@ -90,7 +90,7 @@ func (b *SimulatedBackend) Rollback() {
|
|||
func (b *SimulatedBackend) rollback() {
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
|
||||
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.
|
||||
|
@ -279,7 +279,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
|||
block.AddTx(tx)
|
||||
})
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,15 @@
|
|||
package abi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
errBadBool = errors.New("abi: improperly encoded boolean value")
|
||||
)
|
||||
|
||||
// formatSliceString formats the reflection kind with the given slice size
|
||||
// and returns a formatted string representation.
|
||||
func formatSliceString(kind reflect.Kind, sliceSize int) string {
|
||||
|
|
|
@ -39,7 +39,7 @@ type Method struct {
|
|||
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
|
||||
if len(args) != len(method.Inputs) {
|
||||
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs))
|
||||
|
|
|
@ -62,19 +62,6 @@ func U256(n *big.Int) []byte {
|
|||
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
|
||||
func isSigned(v reflect.Value) bool {
|
||||
switch v.Type() {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package abi
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"reflect"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
@ -59,8 +60,20 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
|
|||
if reflectValue.Kind() == reflect.Array {
|
||||
reflectValue = mustArrayToByteSlice(reflectValue)
|
||||
}
|
||||
|
||||
return common.RightPadBytes(reflectValue.Bytes(), 32)
|
||||
}
|
||||
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
|
||||
}
|
|
@ -32,30 +32,30 @@ func indirect(v reflect.Value) reflect.Value {
|
|||
|
||||
// reflectIntKind returns the reflect using the given size and
|
||||
// unsignedness.
|
||||
func reflectIntKind(unsigned bool, size int) reflect.Kind {
|
||||
func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) {
|
||||
switch size {
|
||||
case 8:
|
||||
if unsigned {
|
||||
return reflect.Uint8
|
||||
return reflect.Uint8, uint8_t
|
||||
}
|
||||
return reflect.Int8
|
||||
return reflect.Int8, int8_t
|
||||
case 16:
|
||||
if unsigned {
|
||||
return reflect.Uint16
|
||||
return reflect.Uint16, uint16_t
|
||||
}
|
||||
return reflect.Int16
|
||||
return reflect.Int16, int16_t
|
||||
case 32:
|
||||
if unsigned {
|
||||
return reflect.Uint32
|
||||
return reflect.Uint32, uint32_t
|
||||
}
|
||||
return reflect.Int32
|
||||
return reflect.Int32, int32_t
|
||||
case 64:
|
||||
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
|
||||
|
|
|
@ -33,7 +33,7 @@ const (
|
|||
FixedBytesTy
|
||||
BytesTy
|
||||
HashTy
|
||||
FixedpointTy
|
||||
FixedPointTy
|
||||
FunctionTy
|
||||
)
|
||||
|
||||
|
@ -126,13 +126,11 @@ func NewType(t string) (typ Type, err error) {
|
|||
|
||||
switch varType {
|
||||
case "int":
|
||||
typ.Kind = reflectIntKind(false, varSize)
|
||||
typ.Type = big_t
|
||||
typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
|
||||
typ.Size = varSize
|
||||
typ.T = IntTy
|
||||
case "uint":
|
||||
typ.Kind = reflectIntKind(true, varSize)
|
||||
typ.Type = ubig_t
|
||||
typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
|
||||
typ.Size = varSize
|
||||
typ.T = UintTy
|
||||
case "bool":
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -38,7 +38,7 @@ var ErrNotSupported = errors.New("not supported")
|
|||
var ErrInvalidPassphrase = errors.New("invalid passphrase")
|
||||
|
||||
// ErrWalletAlreadyOpen is returned if a wallet is attempted to be opened the
|
||||
// secodn time.
|
||||
// second time.
|
||||
var ErrWalletAlreadyOpen = errors.New("wallet already open")
|
||||
|
||||
// ErrWalletClosed is returned if a wallet is attempted to be opened the
|
||||
|
|
|
@ -134,14 +134,13 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privkey, err := hex.DecodeString(keyJSON.PrivateKey)
|
||||
privkey, err := crypto.HexToECDSA(keyJSON.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.Address = common.BytesToAddress(addr)
|
||||
k.PrivateKey = crypto.ToECDSA(privkey)
|
||||
k.PrivateKey = privkey
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -456,7 +456,6 @@ func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (acco
|
|||
if ks.cache.hasAddress(key.Address) {
|
||||
return accounts.Account{}, fmt.Errorf("account already exists")
|
||||
}
|
||||
|
||||
return ks.importKey(key, passphrase)
|
||||
}
|
||||
|
||||
|
|
3
vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_passphrase.go
generated
vendored
3
vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_passphrase.go
generated
vendored
|
@ -259,7 +259,8 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := crypto.ToECDSA(keyBytes)
|
||||
key := crypto.ToECDSAUnsafe(keyBytes)
|
||||
|
||||
return &Key{
|
||||
Id: uuid.UUID(keyId),
|
||||
Address: crypto.PubkeyToAddress(key.PublicKey),
|
||||
|
|
|
@ -74,7 +74,8 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
|
|||
return nil, err
|
||||
}
|
||||
ethPriv := crypto.Keccak256(plainText)
|
||||
ecKey := crypto.ToECDSA(ethPriv)
|
||||
ecKey := crypto.ToECDSAUnsafe(ethPriv)
|
||||
|
||||
key = &Key{
|
||||
Id: nil,
|
||||
Address: crypto.PubkeyToAddress(ecKey.PublicKey),
|
||||
|
|
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/dupes/1
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/dupes/1
generated
vendored
Normal 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}
|
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/dupes/2
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/dupes/2
generated
vendored
Normal 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}
|
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/dupes/foo
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/dupes/foo
generated
vendored
Normal 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}
|
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/.hiddenfile
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/.hiddenfile
generated
vendored
Normal 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}
|
21
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/README
generated
vendored
Normal file
21
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/README
generated
vendored
Normal 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)
|
|
@ -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}
|
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/aaa
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/aaa
generated
vendored
Normal 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}
|
0
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/empty
generated
vendored
Normal file
0
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/empty
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/foo/fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/foo/fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e
generated
vendored
Normal 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}
|
BIN
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/garbage
generated
vendored
Normal file
BIN
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/garbage
generated
vendored
Normal file
Binary file not shown.
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/no-address
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/no-address
generated
vendored
Normal 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}
|
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/zero
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/zero
generated
vendored
Normal 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}
|
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/zzz
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/keystore/zzz
generated
vendored
Normal 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}
|
|
@ -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"}
|
28
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/v1_test_vector.json
generated
vendored
Normal file
28
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/v1_test_vector.json
generated
vendored
Normal 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"
|
||||
}
|
||||
}
|
97
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/v3_test_vector.json
generated
vendored
Normal file
97
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/v3_test_vector.json
generated
vendored
Normal 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"
|
||||
}
|
||||
}
|
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/very-light-scrypt.json
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/accounts/keystore/testdata/very-light-scrypt.json
generated
vendored
Normal 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}
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
|||
{{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low
|
||||
|
||||
* git build of {{.Env.Commit}}
|
||||
|
||||
-- {{.Author}} {{.Time}}
|
|
@ -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}}
|
|
@ -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/>.
|
|
@ -0,0 +1 @@
|
|||
AUTHORS
|
|
@ -0,0 +1 @@
|
|||
build/bin/{{.Name}} usr/bin
|
|
@ -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 $@
|
|
@ -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 "$@"
|
|
@ -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>
|
|
@ -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>
|
327
vendor/github.com/ethereum/go-ethereum/build/nsis.envvarupdate.nsh
generated
vendored
Normal file
327
vendor/github.com/ethereum/go-ethereum/build/nsis.envvarupdate.nsh
generated
vendored
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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.
BIN
vendor/github.com/ethereum/go-ethereum/build/nsis.simplefc.source.zip
generated
vendored
Normal file
BIN
vendor/github.com/ethereum/go-ethereum/build/nsis.simplefc.source.zip
generated
vendored
Normal file
Binary file not shown.
|
@ -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
|
|
@ -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
Loading…
Reference in New Issue