[Chaos Unicorn] Expose ChaosModeUpdate (#1422)
This commit is contained in:
parent
8fe14e8f23
commit
4c1b6c12e4
|
@ -641,3 +641,15 @@ func ExportNodeLogs() *C.char {
|
|||
}
|
||||
return C.CString(string(data))
|
||||
}
|
||||
|
||||
// ChaosModeUpdate changes the URL of the upstream RPC client.
|
||||
//export ChaosModeUpdate
|
||||
func ChaosModeUpdate(on C.int) *C.char {
|
||||
node := statusBackend.StatusNode()
|
||||
if node == nil {
|
||||
return makeJSONResponse(errors.New("node is not running"))
|
||||
}
|
||||
|
||||
err := node.ChaosModeCheckRPCClientsUpstreamURL(on == 1)
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
|
|
@ -632,3 +632,14 @@ func ExportNodeLogs() string {
|
|||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// ChaosModeUpdate sets the Chaos Mode on or off.
|
||||
func ChaosModeUpdate(on bool) string {
|
||||
node := statusBackend.StatusNode()
|
||||
if node == nil {
|
||||
return makeJSONResponse(errors.New("node is not running"))
|
||||
}
|
||||
|
||||
err := node.ChaosModeCheckRPCClientsUpstreamURL(on)
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -639,6 +640,35 @@ func (n *StatusNode) RPCPrivateClient() *rpc.Client {
|
|||
return n.rpcPrivateClient
|
||||
}
|
||||
|
||||
// ChaosModeCheckRPCClientsUpstreamURL updates RPCClient and RPCPrivateClient upstream URLs,
|
||||
// if defined, without restarting the node. This is required for the Chaos Unicorn Day.
|
||||
// Additionally, if the passed URL is Infura, it changes it to httpstat.us/500.
|
||||
func (n *StatusNode) ChaosModeCheckRPCClientsUpstreamURL(on bool) error {
|
||||
url := n.config.UpstreamConfig.URL
|
||||
|
||||
if on {
|
||||
if strings.Contains(url, "infura.io") {
|
||||
url = "https://httpstat.us/500"
|
||||
}
|
||||
}
|
||||
|
||||
publicClient := n.RPCClient()
|
||||
if publicClient != nil {
|
||||
if err := publicClient.UpdateUpstreamURL(url); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
privateClient := n.RPCPrivateClient()
|
||||
if privateClient != nil {
|
||||
if err := privateClient.UpdateUpstreamURL(url); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureSync waits until blockchain synchronization
|
||||
// is complete and returns.
|
||||
func (n *StatusNode) EnsureSync(ctx context.Context) error {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
|
@ -333,3 +336,50 @@ func TestStatusNodeDiscoverNode(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, net.ParseIP("127.0.0.2").To4(), node.IP())
|
||||
}
|
||||
|
||||
func TestChaosModeCheckRPCClientsUpstreamURL(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, `{
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"result": 1
|
||||
}`)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
config := params.NodeConfig{
|
||||
NoDiscovery: true,
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
UpstreamConfig: params.UpstreamRPCConfig{
|
||||
Enabled: true,
|
||||
// put "infura.io" substring to simulate blocking an actual infura.io URLs
|
||||
URL: ts.URL + "?actualURL=infura.io",
|
||||
},
|
||||
}
|
||||
n := New()
|
||||
require.NoError(t, n.Start(&config))
|
||||
defer func() { require.NoError(t, n.Stop()) }()
|
||||
require.NotNil(t, n.RPCClient())
|
||||
|
||||
client := n.RPCClient()
|
||||
require.NotNil(t, client)
|
||||
|
||||
err := client.Call(nil, "net_version")
|
||||
require.NoError(t, err)
|
||||
|
||||
// act
|
||||
err = n.ChaosModeCheckRPCClientsUpstreamURL(true)
|
||||
require.NoError(t, err)
|
||||
|
||||
// assert
|
||||
err = client.Call(nil, "net_version")
|
||||
require.EqualError(t, err, `500 Internal Server Error "500 Internal Server Error"`)
|
||||
|
||||
// act
|
||||
err = n.ChaosModeCheckRPCClientsUpstreamURL(false)
|
||||
require.NoError(t, err)
|
||||
|
||||
// assert
|
||||
err = client.Call(nil, "net_version")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ type Handler func(context.Context, ...interface{}) (interface{}, error)
|
|||
// scheme. It automatically decides where RPC call
|
||||
// goes - Upstream or Local node.
|
||||
type Client struct {
|
||||
sync.RWMutex
|
||||
|
||||
upstreamEnabled bool
|
||||
upstreamURL string
|
||||
|
||||
|
@ -72,6 +74,25 @@ func NewClient(client *gethrpc.Client, upstream params.UpstreamRPCConfig) (*Clie
|
|||
return &c, nil
|
||||
}
|
||||
|
||||
// UpdateUpstreamURL changes the upstream RPC client URL, if the upstream is enabled.
|
||||
func (c *Client) UpdateUpstreamURL(url string) error {
|
||||
if c.upstream == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
rpcClient, err := gethrpc.Dial(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
c.upstream = rpcClient
|
||||
c.upstreamURL = url
|
||||
c.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Call performs a JSON-RPC call with the given arguments and unmarshals into
|
||||
// result if no error occurred.
|
||||
//
|
||||
|
@ -118,7 +139,10 @@ func (c *Client) CallContextIgnoringLocalHandlers(ctx context.Context, result in
|
|||
}
|
||||
|
||||
if c.router.routeRemote(method) {
|
||||
return c.upstream.CallContext(ctx, result, method, args...)
|
||||
c.RLock()
|
||||
client := c.upstream
|
||||
c.RUnlock()
|
||||
return client.CallContext(ctx, result, method, args...)
|
||||
}
|
||||
|
||||
return c.local.CallContext(ctx, result, method, args...)
|
||||
|
|
|
@ -76,3 +76,41 @@ func TestBlockedRoutesRawCall(t *testing.T) {
|
|||
require.Contains(t, rawResult, fmt.Sprintf(`{"code":-32700,"message":"%s"}`, ErrMethodNotFound))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateUpstreamURL(t *testing.T) {
|
||||
ts := createTestServer("")
|
||||
defer ts.Close()
|
||||
|
||||
updatedUpstreamTs := createTestServer("")
|
||||
defer updatedUpstreamTs.Close()
|
||||
|
||||
gethRPCClient, err := gethrpc.Dial(ts.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := NewClient(gethRPCClient, params.UpstreamRPCConfig{Enabled: true, URL: ts.URL})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ts.URL, c.upstreamURL)
|
||||
|
||||
// cache the original upstream client
|
||||
originalUpstreamClient := c.upstream
|
||||
|
||||
err = c.UpdateUpstreamURL(updatedUpstreamTs.URL)
|
||||
require.NoError(t, err)
|
||||
// the upstream cleint instance should change
|
||||
require.NotEqual(t, originalUpstreamClient, c.upstream)
|
||||
require.Equal(t, updatedUpstreamTs.URL, c.upstreamURL)
|
||||
}
|
||||
|
||||
func createTestServer(resp string) *httptest.Server {
|
||||
if resp == "" {
|
||||
resp = `{
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"result": "0x234234e22b9ffc2387e18636e0534534a3d0c56b0243567432453264c16e78a2adc"
|
||||
}`
|
||||
}
|
||||
|
||||
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, resp)
|
||||
}))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue