From 9f696191f29a4b036d7c77d46df59797342db670 Mon Sep 17 00:00:00 2001 From: Silas Davis <silas@monax.io> Date: Fri, 6 Apr 2018 18:23:07 +0100 Subject: [PATCH] Make sure TransactAndHold listens for root call to return. Fixes #715 on github. Signed-off-by: Silas Davis <silas@monax.io> --- event/convention.go | 1 + execution/evm/events/events.go | 27 +++++++++++++++++-------- execution/evm/vm.go | 17 +++++++++++----- execution/evm/vm_test.go | 3 ++- execution/transactor.go | 2 +- rpc/tm/integration/websocket_helpers.go | 4 ++-- rpc/v0/client.go | 20 ++++++++++++++++++ rpc/v0/integration/v0_test.go | 21 ++++++++++++++----- 8 files changed, 73 insertions(+), 22 deletions(-) diff --git a/event/convention.go b/event/convention.go index 450ebf73..33a66a50 100644 --- a/event/convention.go +++ b/event/convention.go @@ -11,6 +11,7 @@ const ( MessageTypeKey = "MessageType" TxTypeKey = "TxType" TxHashKey = "TxHash" + StackDepthKey = "StackDepth" ) // Get a query that matches events with a specific eventID diff --git a/execution/evm/events/events.go b/execution/evm/events/events.go index af90a399..a9308bb5 100644 --- a/execution/evm/events/events.go +++ b/execution/evm/events/events.go @@ -33,11 +33,12 @@ func EventStringLogEvent(addr acm.Address) string { return fmt.Sprintf("Log/% // EventDataCall fires when we call a contract, and when a contract calls another contract type EventDataCall struct { - CallData *CallData - Origin acm.Address - TxID []byte - Return []byte - Exception string + CallData *CallData + Origin acm.Address + TxHash []byte + StackDepth int + Return []byte + Exception string } type CallData struct { @@ -58,9 +59,11 @@ type EventDataLog struct { // Publish/Subscribe -// Subscribe to account call event - if TxHash is provided listens for a specifc Tx otherwise captures all +// Subscribe to account call event - if TxHash is provided listens for a specifc Tx otherwise captures all, if +// stackDepth is greater than or equal to 0 captures calls at a specific stack depth (useful for capturing the return +// of the root call over recursive calls func SubscribeAccountCall(ctx context.Context, subscribable event.Subscribable, subscriber string, address acm.Address, - txHash []byte, ch chan<- *EventDataCall) error { + txHash []byte, stackDepth int, ch chan<- *EventDataCall) error { query := event.QueryForEventID(EventStringAccountCall(address)) @@ -68,6 +71,10 @@ func SubscribeAccountCall(ctx context.Context, subscribable event.Subscribable, query = query.AndEquals(event.TxHashKey, hex.EncodeUpperToString(txHash)) } + if stackDepth >= 0 { + query = query.AndEquals(event.StackDepthKey, stackDepth) + } + return event.SubscribeCallback(ctx, subscribable, subscriber, query, func(message interface{}) bool { eventDataCall, ok := message.(*EventDataCall) if ok { @@ -93,7 +100,11 @@ func SubscribeLogEvent(ctx context.Context, subscribable event.Subscribable, sub func PublishAccountCall(publisher event.Publisher, address acm.Address, eventDataCall *EventDataCall) error { return event.PublishWithEventID(publisher, EventStringAccountCall(address), eventDataCall, - map[string]interface{}{"address": address, event.TxHashKey: hex.EncodeUpperToString(eventDataCall.TxID)}) + map[string]interface{}{ + "address": address, + event.TxHashKey: hex.EncodeUpperToString(eventDataCall.TxHash), + event.StackDepthKey: eventDataCall.StackDepth, + }) } func PublishLogEvent(publisher event.Publisher, address acm.Address, eventDataLog *EventDataLog) error { diff --git a/execution/evm/vm.go b/execution/evm/vm.go index f94cf768..1837b47d 100644 --- a/execution/evm/vm.go +++ b/execution/evm/vm.go @@ -159,11 +159,18 @@ func (vm *VM) fireCallEvent(exception *string, output *[]byte, callerAddress, ca // fire the post call event (including exception if applicable) if vm.publisher != nil { events.PublishAccountCall(vm.publisher, calleeAddress, &events.EventDataCall{ - &events.CallData{Caller: callerAddress, Callee: calleeAddress, Data: input, Value: value, Gas: *gas}, - vm.origin, - vm.txHash, - *output, - *exception, + CallData: &events.CallData{ + Caller: callerAddress, + Callee: calleeAddress, + Data: input, + Value: value, + Gas: *gas, + }, + Origin: vm.origin, + TxHash: vm.txHash, + StackDepth: vm.stackDepth, + Return: *output, + Exception: *exception, }) } } diff --git a/execution/evm/vm_test.go b/execution/evm/vm_test.go index 82d79012..27ce0770 100644 --- a/execution/evm/vm_test.go +++ b/execution/evm/vm_test.go @@ -442,7 +442,8 @@ func runVM(eventCh chan<- *evm_events.EventDataCall, ourVm *VM, caller, callee a emitter := event.NewEmitter(logging.NewNoopLogger()) fmt.Printf("subscribe to %s\n", subscribeAddr) - err := evm_events.SubscribeAccountCall(context.Background(), emitter, "test", subscribeAddr, nil, eventCh) + err := evm_events.SubscribeAccountCall(context.Background(), emitter, "test", subscribeAddr, + nil, -1, eventCh) if err != nil { return nil, err } diff --git a/execution/transactor.go b/execution/transactor.go index ddbe8fe7..662407ec 100644 --- a/execution/transactor.go +++ b/execution/transactor.go @@ -276,7 +276,7 @@ func (trans *Transactor) TransactAndHold(privKey []byte, address *acm.Address, d } err = evm_events.SubscribeAccountCall(context.Background(), trans.eventEmitter, subID, receipt.ContractAddress, - receipt.TxHash, wc) + receipt.TxHash, 0, wc) if err != nil { return nil, err } diff --git a/rpc/tm/integration/websocket_helpers.go b/rpc/tm/integration/websocket_helpers.go index ec1c7ff2..cbaa5749 100644 --- a/rpc/tm/integration/websocket_helpers.go +++ b/rpc/tm/integration/websocket_helpers.go @@ -302,9 +302,9 @@ func unmarshalValidateCall(origin acm.Address, returnCode []byte, txid *[]byte) if !bytes.Equal(ret, returnCode) { return true, fmt.Errorf("call did not return correctly. Got %x, expected %x", ret, returnCode) } - if !bytes.Equal(data.TxID, *txid) { + if !bytes.Equal(data.TxHash, *txid) { return true, fmt.Errorf("TxIDs do not match up! Got %x, expected %x", - data.TxID, *txid) + data.TxHash, *txid) } return true, nil } diff --git a/rpc/v0/client.go b/rpc/v0/client.go index 791f8931..8f635e17 100644 --- a/rpc/v0/client.go +++ b/rpc/v0/client.go @@ -7,7 +7,9 @@ import ( "net/http" "time" + "github.com/hyperledger/burrow/execution/evm/events" "github.com/hyperledger/burrow/rpc" + "github.com/hyperledger/burrow/txs" ) type V0Client struct { @@ -33,6 +35,24 @@ func NewV0Client(url string) *V0Client { } } +func (vc *V0Client) Transact(param TransactParam) (*txs.Receipt, error) { + receipt := new(txs.Receipt) + err := vc.Call(TRANSACT, param, receipt) + if err != nil { + return nil, err + } + return receipt, nil +} + +func (vc *V0Client) TransactAndHold(param TransactParam) (*events.EventDataCall, error) { + eventDataCall := new(events.EventDataCall) + err := vc.Call(TRANSACT_AND_HOLD, param, eventDataCall) + if err != nil { + return nil, err + } + return eventDataCall, nil +} + func (vc *V0Client) Call(method string, param interface{}, result interface{}) error { // Marhsal into JSONRPC request object bs, err := vc.codec.EncodeBytes(param) diff --git a/rpc/v0/integration/v0_test.go b/rpc/v0/integration/v0_test.go index 433b2fae..91ef3715 100644 --- a/rpc/v0/integration/v0_test.go +++ b/rpc/v0/integration/v0_test.go @@ -21,25 +21,36 @@ import ( "testing" "github.com/hyperledger/burrow/rpc/v0" - "github.com/hyperledger/burrow/txs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestTransact(t *testing.T) { cli := v0.NewV0Client("http://localhost:1337/rpc") - receipt := new(txs.Receipt) address := privateAccounts[1].Address() - param := v0.TransactParam{ + receipt, err := cli.Transact(v0.TransactParam{ PrivKey: privateAccounts[0].PrivateKey().RawBytes(), Address: address.Bytes(), Data: []byte{}, Fee: 2, GasLimit: 10000, - } - err := cli.Call(v0.TRANSACT, param, receipt) + }) require.NoError(t, err) assert.False(t, receipt.CreatesContract) assert.Equal(t, address, receipt.ContractAddress) } + +func TestTransactAndHold(t *testing.T) { + cli := v0.NewV0Client("http://localhost:1337/rpc") + + call, err := cli.TransactAndHold(v0.TransactParam{ + PrivKey: privateAccounts[0].PrivateKey().RawBytes(), + Address: nil, + Data: []byte{}, + Fee: 2, + GasLimit: 10000, + }) + require.NoError(t, err) + assert.Equal(t, 0, call.StackDepth) +} -- GitLab