ethereum, RPC API

RPC supports 4 different transports:

  • InProc
  • IPC
  • WS
  • HTTP

Init

When node startup, APIs are registered as call back.

In Node.startInProc(), all APIs will be registered as RPC callbacks.


// startInProc initializes an in-process RPC endpoint.
func (n *Node) startInProc(apis []rpc.API) error {
	// Register all the APIs exposed by the services
	handler := rpc.NewServer()
	for _, api := range apis {
		if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
			return err
		}
		n.log.Debug("InProc registered", "namespace", api.Namespace)
	}
	n.inprocHandler = handler
	return nil
}

call stack:

github.com/ethereum/go-ethereum/rpc.(*serviceRegistry).registerName at service.go:89
github.com/ethereum/go-ethereum/rpc.(*Server).RegisterName at server.go:66
github.com/ethereum/go-ethereum/node.(*Node).startInProc at node.go:315
github.com/ethereum/go-ethereum/node.(*Node).startRPC at node.go:287
github.com/ethereum/go-ethereum/node.(*Node).Start at node.go:239
github.com/ethereum/go-ethereum/cmd/utils.StartNode at cmd.go:67
main.startNode at main.go:331
main.geth at main.go:308
gopkg.in/urfave/cli%2ev1.HandleAction at app.go:490
gopkg.in/urfave/cli%2ev1.(*App).Run at app.go:264
main.main at main.go:248
runtime.main at proc.go:203
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
runtime.rt0_go at asm_amd64.s:220

IPC, WS, HTTP have the similar mechanism of registering callbacks.

See:
StartHTTPEndpoint
StartWSEndpoint
StartIPCEndpoint

Start

In general, RPC server listens and wait for inbound connection and then start a goroutine to dispatch all RPC requests.

// StartIPCEndpoint starts an IPC endpoint.
func StartIPCEndpoint(ipcEndpoint string, apis []API) (net.Listener, *Server, error) {
	// Register all the APIs exposed by the services.
	handler := NewServer()
	for _, api := range apis {
		if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
			return nil, nil, err
		}
		log.Debug("IPC registered", "namespace", api.Namespace)
	}
	// All APIs registered, start the IPC listener.
	listener, err := ipcListen(ipcEndpoint)
	if err != nil {
		return nil, nil, err
	}
	go handler.ServeListener(listener)
	return listener, handler, nil
}

// ServeListener accepts connections on l, serving JSON-RPC on them.
func (s *Server) ServeListener(l net.Listener) error {
	for {
		conn, err := l.Accept()
		if netutil.IsTemporaryError(err) {
			log.Warn("RPC accept error", "err", err)
			continue
		} else if err != nil {
			return err
		}
		log.Trace("Accepted RPC connection", "conn", conn.RemoteAddr())
		go s.ServeCodec(NewCodec(conn), 0)
	}
}


func initClient(conn ServerCodec, idgen func() ID, services *serviceRegistry) *Client {
	_, isHTTP := conn.(*httpConn)
	c := &Client{
		idgen:       idgen,
		isHTTP:      isHTTP,
		services:    services,
		writeConn:   conn,
		close:       make(chan struct{}),
		closing:     make(chan struct{}),
		didClose:    make(chan struct{}),
		reconnected: make(chan ServerCodec),
		readOp:      make(chan readOp),
		readErr:     make(chan error),
		reqInit:     make(chan *requestOp),
		reqSent:     make(chan error, 1),
		reqTimeout:  make(chan *requestOp),
	}
	if !isHTTP {
		go c.dispatch(conn)
	}
	return c
}

The dispatch() will spawn a gorouting to read op from codec, and run a loop for hanlding op.

ServerCodec

// ServerCodec implements reading, parsing and writing RPC messages for the server side of
// a RPC session. Implementations must be go-routine safe since the codec can be called in
// multiple go-routines concurrently.
type ServerCodec interface {
	readBatch() (msgs []*jsonrpcMessage, isBatch bool, err error)
	close()
	jsonWriter
}
  • httpCodec, RPC client that connects to an RPC server over HTTP
  • jsonCodec, JSON-RPC messages to the underlying connection

InProc

DialInProc makes a pipe, for communicatio between server and client.

github.com/ethereum/go-ethereum/rpc.initClient at client.go:206
github.com/ethereum/go-ethereum/rpc.newClient at client.go:200
github.com/ethereum/go-ethereum/rpc.DialInProc at inproc.go:27
github.com/ethereum/go-ethereum/node.(*Node).Attach at node.go:515
main.startNode at main.go:341
main.geth at main.go:308
gopkg.in/urfave/cli%2ev1.HandleAction at app.go:490
gopkg.in/urfave/cli%2ev1.(*App).Run at app.go:264
main.main at main.go:248
runtime.main at proc.go:203
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
runtime.rt0_go at asm_amd64.s:220

IPC

github.com/ethereum/go-ethereum/rpc.initClient at client.go:206
github.com/ethereum/go-ethereum/rpc.(*Server).ServeCodec at server.go:86
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
github.com/ethereum/go-ethereum/rpc.(*Server).ServeListener at ipc.go:38

WS

HTTP

Invoke Method

Sample call stack of ‘admin.datadir’

dispatch:

github.com/ethereum/go-ethereum/rpc.(*handler).startCallProc at handler.go:221
github.com/ethereum/go-ethereum/rpc.(*handler).handleMsg at handler.go:138
github.com/ethereum/go-ethereum/rpc.(*Client).dispatch at client.go:557
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
github.com/ethereum/go-ethereum/rpc.initClient at client.go:223

goroutine for invokation:

github.com/ethereum/go-ethereum/node.(*PublicAdminAPI).Datadir at api.go:295
runtime.call32 at asm_amd64.s:539
reflect.Value.call at value.go:460
reflect.Value.Call at value.go:321
github.com/ethereum/go-ethereum/rpc.(*callback).call at service.go:206
github.com/ethereum/go-ethereum/rpc.(*handler).runMethod at handler.go:369
github.com/ethereum/go-ethereum/rpc.(*handler).handleCall at handler.go:331
github.com/ethereum/go-ethereum/rpc.(*handler).handleCallMsg at handler.go:298
github.com/ethereum/go-ethereum/rpc.(*handler).handleMsg.func1 at handler.go:139
github.com/ethereum/go-ethereum/rpc.(*handler).startCallProc.func1 at handler.go:226
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
github.com/ethereum/go-ethereum/rpc.(*handler).startCallProc at handler.go:222

API

modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章