Repository: hyperledger/firefly
Pull request #923 (2022-08-03 21:46:28)

Updates for EVMConnect support (with EthConnect cross-compatibility)
- Support the `TransactionUpdate` type of websocket payload - which just updates the operation, while leaving it in `Pending` status (rather than marking it success/fail)
- Support events with an `0x12345:` address prefix on the signature


Patch:
diff --git a/go.mod b/go.mod
index 7388d6d74..181001fa5 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,7 @@ require (
 	github.com/golang-migrate/migrate/v4 v4.15.2
 	github.com/gorilla/mux v1.8.0
 	github.com/gorilla/websocket v1.5.0
-	github.com/hyperledger/firefly-common v0.1.15
+	github.com/hyperledger/firefly-common v0.1.16
 	github.com/hyperledger/firefly-signer v0.9.12
 	github.com/jarcoal/httpmock v1.1.0
 	github.com/karlseguin/ccache v2.0.3+incompatible
diff --git a/go.sum b/go.sum
index 1cacd7213..145c4e015 100644
--- a/go.sum
+++ b/go.sum
@@ -727,8 +727,8 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT
 github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/hyperledger/firefly-common v0.1.13/go.mod h1:2NqPi5Ud9H6rSlZXkLbotxW7z4EAD89p3/8oNOpm9Gs=
-github.com/hyperledger/firefly-common v0.1.15 h1:hOAMSz+YuGP1ulLstVFoWxrCAB+0OrbnfUO3v4etvEw=
-github.com/hyperledger/firefly-common v0.1.15/go.mod h1:MNbaI2spBsdZYOub6Duj9xueE7Qyu9itOmJ4vE8tjYw=
+github.com/hyperledger/firefly-common v0.1.16 h1:21xidDEKrJhtGdBSRqHN4PfDi7aYxF0HOFuAa04V1AE=
+github.com/hyperledger/firefly-common v0.1.16/go.mod h1:MNbaI2spBsdZYOub6Duj9xueE7Qyu9itOmJ4vE8tjYw=
 github.com/hyperledger/firefly-signer v0.9.12 h1:pCPiGHx1+MbTsIQuRkoQmfWxvpcvtGHVavls0NnH0po=
 github.com/hyperledger/firefly-signer v0.9.12/go.mod h1:GPQRUZOFOAjkLmg8GDjZUjEdUD0gcar+CSVhwltIwyw=
 github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
diff --git a/internal/blockchain/ethereum/ethereum.go b/internal/blockchain/ethereum/ethereum.go
index d7710304a..ac6575bb0 100644
--- a/internal/blockchain/ethereum/ethereum.go
+++ b/internal/blockchain/ethereum/ethereum.go
@@ -348,8 +348,13 @@ func (e *Ethereum) handleReceipt(ctx context.Context, reply fftypes.JSONObject)
 		l.Errorf("Reply cannot be processed - missing fields: %+v", reply)
 		return
 	}
-	updateType := core.OpStatusSucceeded
-	if replyType != "TransactionSuccess" {
+	var updateType core.OpStatus
+	switch replyType {
+	case "TransactionSuccess":
+		updateType = core.OpStatusSucceeded
+	case "TransactionUpdate":
+		updateType = core.OpStatusPending
+	default:
 		updateType = core.OpStatusFailed
 	}
 	l.Infof("Received operation update: status=%s request=%s tx=%s message=%s", updateType, requestID, txHash, message)
@@ -387,6 +392,10 @@ func (e *Ethereum) handleMessageBatch(ctx context.Context, messages []interface{
 				return err
 			}
 
+			firstColon := strings.Index(signature, ":")
+			if firstColon >= 0 {
+				signature = signature[firstColon+1:]
+			}
 			switch signature {
 			case broadcastBatchEventSignature:
 				if err := e.handleBatchPinEvent(eventCtx, location, subInfo, msgJSON); err != nil {
diff --git a/internal/coremsgs/en_config_descriptions.go b/internal/coremsgs/en_config_descriptions.go
index cd26b5283..5c0b44421 100644
--- a/internal/coremsgs/en_config_descriptions.go
+++ b/internal/coremsgs/en_config_descriptions.go
@@ -328,6 +328,4 @@ var (
 	ConfigPluginsAuth     = ffc("config.plugins.auth", "Authorization plugin configuration", i18n.MapStringStringType)
 	ConfigPluginsAuthName = ffc("config.plugins.auth[].name", "The name of the auth plugin to use", i18n.StringType)
 	ConfigPluginsAuthType = ffc("config.plugins.auth[].type", "The type of the auth plugin to use", i18n.StringType)
-
-	ConfigGlobalAuthBasicPasswordFile = ffc("config.global.basic.passwordfile", "The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt.", i18n.StringType)
 )


Test patch:
diff --git a/internal/blockchain/ethereum/ethereum_test.go b/internal/blockchain/ethereum/ethereum_test.go
index 0aa7292fd..b8664c6de 100644
--- a/internal/blockchain/ethereum/ethereum_test.go
+++ b/internal/blockchain/ethereum/ethereum_test.go
@@ -975,7 +975,7 @@ func TestHandleMessageBatchPinOK(t *testing.T) {
 			]
     },
 		"subId": "sb-b5b97a4e-a317-4053-6400-1474650efcb5",
-		"signature": "BatchPin(address,uint256,string,bytes32,bytes32,string,bytes32[])",
+		"signature": "0x1C197604587F046FD40684A8f21f4609FB811A7b:BatchPin(address,uint256,string,bytes32,bytes32,string,bytes32[])",
 		"logIndex": "50",
 		"timestamp": "1620576488"
   },
@@ -1062,7 +1062,7 @@ func TestHandleMessageBatchPinOK(t *testing.T) {
 		"address":          "0x1C197604587F046FD40684A8f21f4609FB811A7b",
 		"blockNumber":      "38011",
 		"logIndex":         "50",
-		"signature":        "BatchPin(address,uint256,string,bytes32,bytes32,string,bytes32[])",
+		"signature":        "0x1C197604587F046FD40684A8f21f4609FB811A7b:BatchPin(address,uint256,string,bytes32,bytes32,string,bytes32[])",
 		"subId":            "sb-b5b97a4e-a317-4053-6400-1474650efcb5",
 		"transactionHash":  "0xc26df2bf1a733e9249372d61eb11bd8662d26c8129df76890b1beb2f6fa72628",
 		"transactionIndex": "0x0",
@@ -1352,6 +1352,90 @@ func TestHandleReceiptTXSuccess(t *testing.T) {
 	em.AssertExpectations(t)
 }
 
+func TestHandleReceiptTXUpdateEVMConnect(t *testing.T) {
+	em := &coremocks.OperationCallbacks{}
+	wsm := &wsmocks.WSClient{}
+	e := &Ethereum{
+		ctx:       context.Background(),
+		topic:     "topic1",
+		callbacks: common.NewBlockchainCallbacks(),
+		wsconn:    wsm,
+	}
+	e.SetOperationHandler("ns1", em)
+
+	var reply fftypes.JSONObject
+	operationID := fftypes.NewUUID()
+	data := fftypes.JSONAnyPtr(`{
+		"created": "2022-08-03T18:55:42.671166Z",
+		"errorHistory": null,
+		"firstSubmit": "2022-08-03T18:55:42.762254Z",
+		"gas": "48049",
+		"gasPrice": 0,
+		"headers": {
+			"requestId": "ns1:` + operationID.String() + `",
+			"type": "TransactionUpdate"
+		},
+		"id": "ns1:` + operationID.String() + `",
+		"lastSubmit": "2022-08-03T18:55:42.762254Z",
+		"nonce": "1",
+		"policyInfo": null,
+		"receipt": {
+			"blockHash": "0x972713d879efd32573fe4d88ed0cde94a094367d50f7e5bc8262dd41fe07d9e6",
+			"blockNumber": "3",
+			"extraInfo": {
+				"blockHash": "0x972713d879efd32573fe4d88ed0cde94a094367d50f7e5bc8262dd41fe07d9e6",
+				"blockNumber": "0x3",
+				"contractAddress": null,
+				"cumulativeGasUsed": "0x7d21",
+				"from": "0x081afaa6792a524ff2fb0654e615d19f9a600e57",
+				"gasUsed": "0x7d21",
+				"logs": [
+					{
+						"address": "0x9da7ecba282387ecd696dd9aecfc14efeb5f5fce",
+						"blockHash": "0x972713d879efd32573fe4d88ed0cde94a094367d50f7e5bc8262dd41fe07d9e6",
+						"blockNumber": "0x3",
+						"data": "0x000000000000000000000000081afaa6792a524ff2fb0654e615d19f9a600e570000000000000000000000000000000000000000000000000000000062eac4ae00000000000000000000000000000000000000000000000000000000000000e05fbe3d02be9341f492917ec5aecfb151d243287ac95c49f780a4259ab53a8d14ec218052055a2b541712ab3246354c36f3aa189e1f31a7a8b33cbf957014d2e6000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d50535551486f5852617553346a5434544b55356f414167616d334d4132315642575777634c6e66536e35696d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018319d70666de18ed7d1c17e1bbd8ac0b16716fbe2059a8ae356a09d3bd067e14",
+						"logIndex": "0x0",
+						"removed": false,
+						"topics": [
+							"0x805721bc246bccc732581be0c0aa2dd8f7ec93e97ba4b307be84428c98b0a12f"
+						],
+						"transactionHash": "0x929c898a46762d91e9f4b0b8e2800863dcf4a40f694109dc4cd19dbd334fa4cc",
+						"transactionIndex": "0x0"
+					}
+				],
+				"status": "0x1",
+				"to": "0x9da7ecba282387ecd696dd9aecfc14efeb5f5fce",
+				"transactionHash": "0x929c898a46762d91e9f4b0b8e2800863dcf4a40f694109dc4cd19dbd334fa4cc",
+				"transactionIndex": "0x0"
+			},
+			"success": true,
+			"transactionIndex": "0"
+		},
+		"sequenceId": "dfd7c5e6-135d-11ed-80ff-b67a78953577",
+		"status": "Succeeded",
+		"transactionData": "0x48ce1dcc5fbe3d02be9341f492917ec5aecfb151d243287ac95c49f780a4259ab53a8d14ec218052055a2b541712ab3246354c36f3aa189e1f31a7a8b33cbf957014d2e6000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002e516d50535551486f5852617553346a5434544b55356f414167616d334d4132315642575777634c6e66536e35696d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018319d70666de18ed7d1c17e1bbd8ac0b16716fbe2059a8ae356a09d3bd067e14",
+		"transactionHash": "0x929c898a46762d91e9f4b0b8e2800863dcf4a40f694109dc4cd19dbd334fa4cc",
+		"transactionHeaders": {
+			"from": "0x081afaa6792a524ff2fb0654e615d19f9a600e57",
+			"to": "0x9da7ecba282387ecd696dd9aecfc14efeb5f5fce"
+		},
+		"updated": "2022-08-03T18:55:43.781941Z"
+	}`)
+
+	em.On("OperationUpdate", e, mock.MatchedBy(func(update *core.OperationUpdate) bool {
+		return update.NamespacedOpID == "ns1:"+operationID.String() &&
+			update.Status == core.OpStatusPending &&
+			update.BlockchainTXID == "0x929c898a46762d91e9f4b0b8e2800863dcf4a40f694109dc4cd19dbd334fa4cc"
+	})).Return(nil)
+
+	err := json.Unmarshal(data.Bytes(), &reply)
+	assert.NoError(t, err)
+	e.handleReceipt(context.Background(), reply)
+
+	em.AssertExpectations(t)
+}
+
 func TestHandleBadPayloadsAndThenReceiptFailure(t *testing.T) {
 	e, cancel := newTestEthereum()
 	defer cancel()