diff --git a/.circleci/config.yml b/.circleci/config.yml index 41554074416f5332957b66d22b43eef4a2885256..f09a13f05a04ca6fb8512662d9bb9d05ed95d3b6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,7 +50,6 @@ jobs: # This allows us to perform our docker builds - setup_remote_docker: <<: *setup_docker - - run: docker login -u $DOCKER_USER -p $DOCKER_PASS quay.io # build docker image and tag the docker image(s) depending on branch/tag - run: make build_docker_db - run: docker save quay.io/monax/db > db-images.tar @@ -67,7 +66,6 @@ jobs: at: . - setup_remote_docker: <<: *setup_docker - - run: docker login -u $DOCKER_USER -p $DOCKER_PASS quay.io - run: docker load -i db-images.tar - run: docker run quay.io/monax/db:$(./scripts/local_version.sh) burrow -h diff --git a/Makefile b/Makefile index eb07a164ecd101f16cee9cfe40003552ab7b4cb8..293c287cfc4ffd8cb1ae05969f937e69eaadc25e 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,8 @@ SHELL := /bin/bash REPO := $(shell pwd) -GOFILES_NOVENDOR := $(shell find ${REPO} -type f -name '*.go' -not -path "${REPO}/vendor/*") -PACKAGES_NOVENDOR := $(shell go list ./... | grep -vF /vendor/) +GOFILES_NOVENDOR := $(shell go list -f "{{.Dir}}" ./...) +PACKAGES_NOVENDOR := $(shell go list ./...) # Bosmarmot integration testing BOSMARMOT_PROJECT := github.com/monax/bosmarmot BOSMARMOT_GOPATH := ${REPO}/.gopath_bos @@ -94,7 +94,7 @@ build: check build_db build_client # build all targets in github.com/hyperledger/burrow with checks for race conditions .PHONY: build_race -build_race: check build_race_db build_race_clien +build_race: check build_race_db build_race_client # build burrow .PHONY: build_db diff --git a/account/address.go b/account/address.go index 2352539741815eac1383c43c33cf3792cb407163..2340afd48a4fd4c4b52f8beceddc29dd5e1481b6 100644 --- a/account/address.go +++ b/account/address.go @@ -15,14 +15,28 @@ const AddressHexLength = 2 * binary.Word160Length var ZeroAddress = Address{} -func AddressFromBytes(addr []byte) (address Address, err error) { - if len(addr) != binary.Word160Length { +// Returns a pointer to an Address that is nil iff len(bs) == 0 otherwise does the same as AddressFromBytes +func MaybeAddressFromBytes(bs []byte) (*Address, error) { + if len(bs) == 0 { + return nil, nil + } + address, err := AddressFromBytes(bs) + if err != nil { + return nil, err + } + return &address, nil +} + +// Returns an address consisting of the first 20 bytes of bs, return an error if the bs does not have length exactly 20 +// but will still return either: the bytes in bs padded on the right or the first 20 bytes of bs truncated in any case. +func AddressFromBytes(bs []byte) (address Address, err error) { + if len(bs) != binary.Word160Length { err = fmt.Errorf("slice passed as address '%X' has %d bytes but should have %d bytes", - addr, len(addr), binary.Word160Length) + bs, len(bs), binary.Word160Length) // It is caller's responsibility to check for errors. If they ignore the error we'll assume they want the - // best-effort mapping of the bytes passed to an address so we don't return here + // best-effort mapping of the bytes passed to an address so we don't return here } - copy(address[:], addr) + copy(address[:], bs) return } diff --git a/core/kernel.go b/core/kernel.go index 5348c70f5a937ffeec364ee66d990e739ada67c7..3562b7302c9553ace4f07250d86d1ce89d32bb19 100644 --- a/core/kernel.go +++ b/core/kernel.go @@ -20,6 +20,7 @@ import ( "os" "os/signal" "sync" + "syscall" "time" bcm "github.com/hyperledger/burrow/blockchain" @@ -127,9 +128,9 @@ func NewKernel(ctx context.Context, privValidator tm_types.PrivValidator, genesi Name: "RPC/V0", Launch: func() (server.Server, error) { codec := v0.NewTCodec() - jsonServer := v0.NewJSONServer(v0.NewJSONService(codec, service)) + jsonServer := v0.NewJSONServer(v0.NewJSONService(codec, service, logger)) websocketServer := v0_server.NewWebSocketServer(rpcConfig.V0.Server.WebSocket.MaxWebSocketSessions, - v0.NewWebsocketService(codec, service), logger) + v0.NewWebsocketService(codec, service, logger), logger) serveProcess, err := v0_server.NewServeProcess(rpcConfig.V0.Server, logger, jsonServer, websocketServer) if err != nil { @@ -179,8 +180,10 @@ func (kern *Kernel) supervise() { // TODO: Consider capturing kernel panics from boot and sending them here via a channel where we could // perform disaster restarts of the kernel; rejoining the network as if we were a new node. signals := make(chan os.Signal, 1) - signal.Notify(signals, os.Interrupt, os.Kill) - <-signals + signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL) + sig := <-signals + logging.InfoMsg(kern.logger, fmt.Sprintf("Caught %v signal so shutting down", sig), + "signal", sig.String()) kern.Shutdown(context.Background()) } diff --git a/execution/transactor.go b/execution/transactor.go index 2fc71f0a5eb1c54048f8e554cfb7ec3d02ddc492..552d3d888379342edccc557a6e1523027ecb9283 100644 --- a/execution/transactor.go +++ b/execution/transactor.go @@ -48,8 +48,8 @@ type Transactor interface { CallCode(fromAddress acm.Address, code, data []byte) (*Call, error) BroadcastTx(tx txs.Tx) (*txs.Receipt, error) BroadcastTxAsync(tx txs.Tx, callback func(res *abci_types.Response)) error - Transact(privKey []byte, address acm.Address, data []byte, gasLimit, fee uint64) (*txs.Receipt, error) - TransactAndHold(privKey []byte, address acm.Address, data []byte, gasLimit, fee uint64) (*evm_events.EventDataCall, error) + Transact(privKey []byte, address *acm.Address, data []byte, gasLimit, fee uint64) (*txs.Receipt, error) + TransactAndHold(privKey []byte, address *acm.Address, data []byte, gasLimit, fee uint64) (*evm_events.EventDataCall, error) Send(privKey []byte, toAddress acm.Address, amount uint64) (*txs.Receipt, error) SendAndHold(privKey []byte, toAddress acm.Address, amount uint64) (*txs.Receipt, error) TransactNameReg(privKey []byte, name, data string, amount, fee uint64) (*txs.Receipt, error) @@ -58,7 +58,7 @@ type Transactor interface { // Transactor is the controller/middleware for the v0 RPC type transactor struct { - txMtx *sync.Mutex + txMtx sync.Mutex blockchain blockchain.Blockchain state acm.StateReader eventEmitter event.Emitter @@ -169,7 +169,7 @@ func (trans *transactor) BroadcastTx(tx txs.Tx) (*txs.Receipt, error) { } // Orders calls to BroadcastTx using lock (waits for response from core before releasing) -func (trans *transactor) Transact(privKey []byte, address acm.Address, data []byte, gasLimit, +func (trans *transactor) Transact(privKey []byte, address *acm.Address, data []byte, gasLimit, fee uint64) (*txs.Receipt, error) { if len(privKey) != 64 { @@ -209,7 +209,7 @@ func (trans *transactor) Transact(privKey []byte, address acm.Address, data []by } tx := &txs.CallTx{ Input: txInput, - Address: &address, + Address: address, GasLimit: gasLimit, Fee: fee, Data: data, @@ -223,19 +223,14 @@ func (trans *transactor) Transact(privKey []byte, address acm.Address, data []by return trans.BroadcastTx(txS) } -func (trans *transactor) TransactAndHold(privKey []byte, address acm.Address, data []byte, gasLimit, +func (trans *transactor) TransactAndHold(privKey []byte, address *acm.Address, data []byte, gasLimit, fee uint64) (*evm_events.EventDataCall, error) { receipt, err := trans.Transact(privKey, address, data, gasLimit, fee) if err != nil { return nil, err } - var addr acm.Address - if receipt.CreatesContract { - addr = receipt.ContractAddr - } else { - addr = address - } + // We want non-blocking on the first event received (but buffer the value), // after which we want to block (and then discard the value - see below) wc := make(chan *evm_events.EventDataCall, 1) @@ -245,7 +240,8 @@ func (trans *transactor) TransactAndHold(privKey []byte, address acm.Address, da return nil, err } - err = evm_events.SubscribeAccountCall(context.Background(), trans.eventEmitter, subID, addr, receipt.TxHash, wc) + err = evm_events.SubscribeAccountCall(context.Background(), trans.eventEmitter, subID, receipt.ContractAddress, + receipt.TxHash, wc) if err != nil { return nil, err } diff --git a/rpc/result_test.go b/rpc/result_test.go index 11dc2b8ffd3ab900ddc4f0bf360a41f2745ee361..d275011305bb73617805140b91e324161e8cbf80 100644 --- a/rpc/result_test.go +++ b/rpc/result_test.go @@ -31,14 +31,14 @@ func TestResultBroadcastTx(t *testing.T) { // Make sure these are unpacked as expected res := ResultBroadcastTx{ Receipt: txs.Receipt{ - ContractAddr: acm.Address{0, 2, 3}, + ContractAddress: acm.Address{0, 2, 3}, CreatesContract: true, TxHash: []byte("foo"), }, } js := string(wire.JSONBytes(res)) - assert.Equal(t, `{"Receipt":{"TxHash":"666F6F","CreatesContract":true,"ContractAddr":"0002030000000000000000000000000000000000"}}`, js) + assert.Equal(t, `{"Receipt":{"TxHash":"666F6F","CreatesContract":true,"ContractAddress":"0002030000000000000000000000000000000000"}}`, js) res2 := new(ResultBroadcastTx) wire.ReadBinaryBytes(wire.BinaryBytes(res), res2) diff --git a/rpc/tm/integration/client_test.go b/rpc/tm/integration/client_test.go index 561eca764ee41a6eac6876c2d9f3c35778d94252..bf62e6c7be72403145be18d2667ffafea5a69af9 100644 --- a/rpc/tm/integration/client_test.go +++ b/rpc/tm/integration/client_test.go @@ -108,7 +108,7 @@ func TestGetStorage(t *testing.T) { " create a contract") assert.NotEqual(t, 0, len(receipt.TxHash), "Receipt should contain a"+ " transaction hash") - contractAddr := receipt.ContractAddr + contractAddr := receipt.ContractAddress assert.NotEqual(t, 0, len(contractAddr), "Transactions claims to have"+ " created a contract but the contract address is empty") @@ -165,7 +165,7 @@ func TestCallContract(t *testing.T) { " create a contract") assert.NotEqual(t, 0, len(receipt.TxHash), "Receipt should contain a"+ " transaction hash") - contractAddr := receipt.ContractAddr + contractAddr := receipt.ContractAddress assert.NotEqual(t, 0, len(contractAddr), "Transactions claims to have"+ " created a contract but the contract address is empty") diff --git a/rpc/tm/integration/websocket_client_test.go b/rpc/tm/integration/websocket_client_test.go index deb310abd3312ba5c123923f23a71c23a2d5848f..e13e817efc78206fbc27b08ff51324b5fd3c5877 100644 --- a/rpc/tm/integration/websocket_client_test.go +++ b/rpc/tm/integration/websocket_client_test.go @@ -167,7 +167,7 @@ func TestWSCallWait(t *testing.T) { waitForEvent(t, wsc, eid1, func() { tx := makeDefaultCallTx(t, jsonRpcClient, nil, code, amt, gasLim, fee) receipt := broadcastTx(t, jsonRpcClient, tx) - contractAddr = receipt.ContractAddr + contractAddr = receipt.ContractAddress }, unmarshalValidateTx(amt, returnCode)) // susbscribe to the new contract @@ -182,7 +182,7 @@ func TestWSCallWait(t *testing.T) { waitForEvent(t, wsc, eid2, func() { tx := makeDefaultCallTx(t, jsonRpcClient, &contractAddr, data, amt, gasLim, fee) receipt := broadcastTx(t, jsonRpcClient, tx) - contractAddr = receipt.ContractAddr + contractAddr = receipt.ContractAddress }, unmarshalValidateTx(amt, returnVal)) } @@ -200,7 +200,7 @@ func TestWSCallNoWait(t *testing.T) { tx := makeDefaultCallTx(t, jsonRpcClient, nil, code, amt, gasLim, fee) receipt, err := broadcastTxAndWaitForBlock(t, jsonRpcClient, wsc, tx) require.NoError(t, err) - contractAddr := receipt.ContractAddr + contractAddr := receipt.ContractAddress // susbscribe to the new contract amt = uint64(10001) @@ -230,7 +230,7 @@ func TestWSCallCall(t *testing.T) { tx := makeDefaultCallTx(t, jsonRpcClient, nil, code, amt, gasLim, fee) receipt, err := broadcastTxAndWaitForBlock(t, jsonRpcClient, wsc, tx) require.NoError(t, err) - contractAddr1 := receipt.ContractAddr + contractAddr1 := receipt.ContractAddress // subscribe to the new contracts eid := evm_events.EventStringAccountCall(contractAddr1) @@ -240,7 +240,7 @@ func TestWSCallCall(t *testing.T) { code, _, _ = simpleCallContract(contractAddr1) tx = makeDefaultCallTx(t, jsonRpcClient, nil, code, amt, gasLim, fee) receipt = broadcastTx(t, jsonRpcClient, tx) - contractAddr2 := receipt.ContractAddr + contractAddr2 := receipt.ContractAddress // let the contract get created first waitForEvent(t, wsc, eid, diff --git a/rpc/v0/json_service.go b/rpc/v0/json_service.go index 78d87dd400c9a9f2724209992e99d410446b7ec4..50cad08a41326059d6cd6838d74ee3aab2b49eea 100644 --- a/rpc/v0/json_service.go +++ b/rpc/v0/json_service.go @@ -20,6 +20,8 @@ import ( "net/http" "github.com/gin-gonic/gin" + "github.com/hyperledger/burrow/logging" + logging_types "github.com/hyperledger/burrow/logging/types" "github.com/hyperledger/burrow/rpc" "github.com/hyperledger/burrow/rpc/v0/server" ) @@ -83,18 +85,20 @@ type JSONService struct { service rpc.Service eventSubs *Subscriptions defaultHandlers map[string]RequestHandlerFunc + logger logging_types.InfoTraceLogger } // Create a new JSON-RPC 2.0 service for burrow (tendermint). -func NewJSONService(codec rpc.Codec, service rpc.Service) server.HttpService { +func NewJSONService(codec rpc.Codec, service rpc.Service, logger logging_types.InfoTraceLogger) server.HttpService { tmhttps := &JSONService{ codec: codec, service: service, eventSubs: NewSubscriptions(service), + logger: logging.WithScope(logger, "NewJSONService"), } - dhMap := GetMethods(codec, service) + dhMap := GetMethods(codec, service, tmhttps.logger) // Events dhMap[EVENT_SUBSCRIBE] = tmhttps.EventSubscribe dhMap[EVENT_UNSUBSCRIBE] = tmhttps.EventUnsubscribe @@ -128,6 +132,10 @@ func (js *JSONService) Process(r *http.Request, w http.ResponseWriter) { mName := req.Method if handler, ok := js.defaultHandlers[mName]; ok { + logging.TraceMsg(js.logger, "Request received", + "id", req.Id, + "method", req.Method, + "params", string(req.Params)) resp, errCode, err := handler(req, w) if err != nil { js.writeError(err.Error(), req.Id, errCode, w) diff --git a/rpc/v0/methods.go b/rpc/v0/methods.go index fdd3eeda5ce6915ff90a2ec6b0ef8c3a8875c764..aa4416b998757c5adc72856ea0c38ba380b04080 100644 --- a/rpc/v0/methods.go +++ b/rpc/v0/methods.go @@ -17,6 +17,7 @@ package v0 import ( acm "github.com/hyperledger/burrow/account" "github.com/hyperledger/burrow/execution" + logging_types "github.com/hyperledger/burrow/logging/types" "github.com/hyperledger/burrow/rpc" "github.com/hyperledger/burrow/rpc/filters" "github.com/hyperledger/burrow/txs" @@ -62,7 +63,7 @@ const ( type RequestHandlerFunc func(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) // Private. Create a method name -> method handler map. -func GetMethods(codec rpc.Codec, service rpc.Service) map[string]RequestHandlerFunc { +func GetMethods(codec rpc.Codec, service rpc.Service, logger logging_types.InfoTraceLogger) map[string]RequestHandlerFunc { accountFilterFactory := filters.NewAccountFilterFactory() nameRegFilterFactory := filters.NewNameRegFilterFactory() @@ -224,7 +225,7 @@ func GetMethods(codec rpc.Codec, service rpc.Service) map[string]RequestHandlerF if err != nil { return nil, rpc.INVALID_PARAMS, err } - address, err := acm.AddressFromBytes(param.Address) + address, err := acm.MaybeAddressFromBytes(param.Address) if err != nil { return nil, rpc.INVALID_PARAMS, err } @@ -240,7 +241,7 @@ func GetMethods(codec rpc.Codec, service rpc.Service) map[string]RequestHandlerF if err != nil { return nil, rpc.INVALID_PARAMS, err } - address, err := acm.AddressFromBytes(param.Address) + address, err := acm.MaybeAddressFromBytes(param.Address) if err != nil { return nil, rpc.INVALID_PARAMS, err } diff --git a/rpc/v0/websocket_service.go b/rpc/v0/websocket_service.go index 7917d84c12489580f19e8dbd50750d29015a3444..4c0072685a8e68bf26eacd0bc9ca371c28c44bdd 100644 --- a/rpc/v0/websocket_service.go +++ b/rpc/v0/websocket_service.go @@ -15,12 +15,13 @@ package v0 import ( + "context" "encoding/json" "fmt" - "context" - "github.com/hyperledger/burrow/event" + "github.com/hyperledger/burrow/logging" + logging_types "github.com/hyperledger/burrow/logging/types" "github.com/hyperledger/burrow/rpc" "github.com/hyperledger/burrow/rpc/v0/server" ) @@ -30,15 +31,17 @@ type WebsocketService struct { codec rpc.Codec service rpc.Service defaultHandlers map[string]RequestHandlerFunc + logger logging_types.InfoTraceLogger } // Create a new websocket service. -func NewWebsocketService(codec rpc.Codec, service rpc.Service) server.WebSocketService { +func NewWebsocketService(codec rpc.Codec, service rpc.Service, logger logging_types.InfoTraceLogger) server.WebSocketService { tmwss := &WebsocketService{ codec: codec, service: service, + logger: logging.WithScope(logger, "NewWebsocketService"), } - dhMap := GetMethods(codec, service) + dhMap := GetMethods(codec, service, tmwss.logger) // Events dhMap[EVENT_SUBSCRIBE] = tmwss.EventSubscribe dhMap[EVENT_UNSUBSCRIBE] = tmwss.EventUnsubscribe diff --git a/txs/tx.go b/txs/tx.go index c9d2e74145eb9a6dd7623e28309412d41f59143b..2d35e77620d8fbc043fd09dba182e37afe85e74f 100644 --- a/txs/tx.go +++ b/txs/tx.go @@ -124,7 +124,7 @@ type ( Receipt struct { TxHash []byte CreatesContract bool - ContractAddr acm.Address + ContractAddress acm.Address } NameTx struct { @@ -410,9 +410,9 @@ func GenerateReceipt(chainId string, tx Tx) Receipt { if callTx, ok := tx.(*CallTx); ok { receipt.CreatesContract = callTx.Address == nil if receipt.CreatesContract { - receipt.ContractAddr = acm.NewContractAddress(callTx.Input.Address, callTx.Input.Sequence) + receipt.ContractAddress = acm.NewContractAddress(callTx.Input.Address, callTx.Input.Sequence) } else { - receipt.ContractAddr = *callTx.Address + receipt.ContractAddress = *callTx.Address } } return receipt