Skip to content

Commit 75b718f

Browse files
committed
Create a Transaction and Operation for contract invoke requests
Signed-off-by: Andrew Richardson <andrew.richardson@kaleido.io>
1 parent afb4c84 commit 75b718f

File tree

5 files changed

+101
-7
lines changed

5 files changed

+101
-7
lines changed

docs/swagger/swagger.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5252,6 +5252,7 @@ paths:
52525252
- token_create_pool
52535253
- token_announce_pool
52545254
- token_transfer
5255+
- contract_invoke
52555256
type: string
52565257
updated: {}
52575258
type: object
@@ -5301,6 +5302,7 @@ paths:
53015302
- batch_pin
53025303
- token_pool
53035304
- token_transfer
5305+
- contract_invoke
53045306
type: string
53055307
type: object
53065308
description: Success
@@ -6010,6 +6012,7 @@ paths:
60106012
- token_create_pool
60116013
- token_announce_pool
60126014
- token_transfer
6015+
- contract_invoke
60136016
type: string
60146017
updated: {}
60156018
type: object
@@ -6075,6 +6078,7 @@ paths:
60756078
- token_create_pool
60766079
- token_announce_pool
60776080
- token_transfer
6081+
- contract_invoke
60786082
type: string
60796083
updated: {}
60806084
type: object
@@ -9976,6 +9980,7 @@ paths:
99769980
- batch_pin
99779981
- token_pool
99789982
- token_transfer
9983+
- contract_invoke
99799984
type: string
99809985
type: object
99819986
description: Success
@@ -10083,6 +10088,7 @@ paths:
1008310088
- batch_pin
1008410089
- token_pool
1008510090
- token_transfer
10091+
- contract_invoke
1008610092
type: string
1008710093
type: object
1008810094
description: Success
@@ -10132,6 +10138,7 @@ paths:
1013210138
- batch_pin
1013310139
- token_pool
1013410140
- token_transfer
10141+
- contract_invoke
1013510142
type: string
1013610143
type: object
1013710144
type: array

internal/contracts/manager.go

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,37 @@ func (cm *contractManager) InvokeContract(ctx context.Context, ns string, req *f
149149
return nil, err
150150
}
151151

152-
if req.Method, err = cm.resolveInvokeContractRequest(ctx, ns, req); err != nil {
153-
return nil, err
154-
}
155-
if err := cm.validateInvokeContractRequest(ctx, req); err != nil {
152+
var op *fftypes.Operation
153+
err = cm.database.RunAsGroup(ctx, func(ctx context.Context) (err error) {
154+
if req.Method, err = cm.resolveInvokeContractRequest(ctx, ns, req); err != nil {
155+
return err
156+
}
157+
if err := cm.validateInvokeContractRequest(ctx, req); err != nil {
158+
return err
159+
}
160+
161+
tx := &fftypes.Transaction{
162+
ID: fftypes.NewUUID(),
163+
Namespace: ns,
164+
Type: fftypes.TransactionTypeContractInvoke,
165+
Created: fftypes.Now(),
166+
Status: fftypes.OpStatusPending,
167+
}
168+
if err := cm.database.UpsertTransaction(ctx, tx); err != nil {
169+
return err
170+
}
171+
172+
op = fftypes.NewTXOperation(
173+
cm.blockchain,
174+
ns,
175+
tx.ID,
176+
"",
177+
fftypes.OpTypeContractInvoke,
178+
fftypes.OpStatusPending)
179+
op.Input = req.Input
180+
return cm.database.InsertOperation(ctx, op)
181+
})
182+
if err != nil {
156183
return nil, err
157184
}
158185

internal/contracts/manager_test.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ func newTestContractManager() *contractManager {
4040
mim := &identitymanagermocks.Manager{}
4141
mbi := &blockchainmocks.Plugin{}
4242

43+
mbi.On("Name").Return("mockblockchain").Maybe()
44+
4345
rag := mdb.On("RunAsGroup", mock.Anything, mock.Anything).Maybe()
4446
rag.RunFn = func(a mock.Arguments) {
4547
rag.ReturnArguments = mock.Arguments{
@@ -1070,6 +1072,7 @@ func TestInvokeContract(t *testing.T) {
10701072
cm := newTestContractManager()
10711073
mbi := cm.blockchain.(*blockchainmocks.Plugin)
10721074
mim := cm.identity.(*identitymanagermocks.Manager)
1075+
mdi := cm.database.(*databasemocks.Plugin)
10731076

10741077
req := &fftypes.ContractCallRequest{
10751078
Type: fftypes.CallTypeInvoke,
@@ -1085,6 +1088,12 @@ func TestInvokeContract(t *testing.T) {
10851088
}
10861089

10871090
mim.On("ResolveSigningKey", mock.Anything, "").Return("key-resolved", nil)
1091+
mdi.On("UpsertTransaction", mock.Anything, mock.MatchedBy(func(tx *fftypes.Transaction) bool {
1092+
return tx.Namespace == "ns1" && tx.Type == fftypes.TransactionTypeContractInvoke
1093+
})).Return(nil)
1094+
mdi.On("InsertOperation", mock.Anything, mock.MatchedBy(func(op *fftypes.Operation) bool {
1095+
return op.Namespace == "ns1" && op.Type == fftypes.OpTypeContractInvoke && op.Plugin == "mockblockchain"
1096+
})).Return(nil)
10881097
mbi.On("InvokeContract", mock.Anything, mock.AnythingOfType("*fftypes.UUID"), "key-resolved", req.Location, req.Method, req.Input).Return(struct{}{}, nil)
10891098

10901099
_, err := cm.InvokeContract(context.Background(), "ns1", req)
@@ -1130,9 +1139,36 @@ func TestInvokeContractFailResolve(t *testing.T) {
11301139
assert.Regexp(t, "FF10313", err)
11311140
}
11321141

1142+
func TestInvokeContractTXFail(t *testing.T) {
1143+
cm := newTestContractManager()
1144+
mim := cm.identity.(*identitymanagermocks.Manager)
1145+
mdi := cm.database.(*databasemocks.Plugin)
1146+
1147+
req := &fftypes.ContractCallRequest{
1148+
Type: fftypes.CallTypeInvoke,
1149+
Interface: fftypes.NewUUID(),
1150+
Ledger: fftypes.JSONAnyPtr(""),
1151+
Location: fftypes.JSONAnyPtr(""),
1152+
Method: &fftypes.FFIMethod{
1153+
Name: "doStuff",
1154+
ID: fftypes.NewUUID(),
1155+
Params: fftypes.FFIParams{},
1156+
Returns: fftypes.FFIParams{},
1157+
},
1158+
}
1159+
1160+
mim.On("ResolveSigningKey", mock.Anything, "").Return("key-resolved", nil)
1161+
mdi.On("UpsertTransaction", mock.Anything, mock.MatchedBy(func(tx *fftypes.Transaction) bool {
1162+
return tx.Namespace == "ns1" && tx.Type == fftypes.TransactionTypeContractInvoke
1163+
})).Return(fmt.Errorf("pop"))
1164+
1165+
_, err := cm.InvokeContract(context.Background(), "ns1", req)
1166+
1167+
assert.EqualError(t, err, "pop")
1168+
}
1169+
11331170
func TestInvokeContractNoMethodSignature(t *testing.T) {
11341171
cm := newTestContractManager()
1135-
mbi := cm.blockchain.(*blockchainmocks.Plugin)
11361172
mim := cm.identity.(*identitymanagermocks.Manager)
11371173

11381174
req := &fftypes.ContractCallRequest{
@@ -1145,7 +1181,6 @@ func TestInvokeContractNoMethodSignature(t *testing.T) {
11451181
}
11461182

11471183
mim.On("ResolveSigningKey", mock.Anything, "").Return("key-resolved", nil)
1148-
mbi.On("InvokeContract", mock.Anything, mock.AnythingOfType("*fftypes.UUID"), "key-resolved", mock.Anything, mock.AnythingOfType("*fftypes.FFIMethod"), mock.Anything).Return(struct{}{}, nil)
11491184

11501185
_, err := cm.InvokeContract(context.Background(), "ns1", req)
11511186

@@ -1220,6 +1255,7 @@ func TestQueryContract(t *testing.T) {
12201255
cm := newTestContractManager()
12211256
mbi := cm.blockchain.(*blockchainmocks.Plugin)
12221257
mim := cm.identity.(*identitymanagermocks.Manager)
1258+
mdi := cm.database.(*databasemocks.Plugin)
12231259

12241260
req := &fftypes.ContractCallRequest{
12251261
Type: fftypes.CallTypeQuery,
@@ -1235,6 +1271,12 @@ func TestQueryContract(t *testing.T) {
12351271
}
12361272

12371273
mim.On("ResolveSigningKey", mock.Anything, "").Return("key-resolved", nil)
1274+
mdi.On("UpsertTransaction", mock.Anything, mock.MatchedBy(func(tx *fftypes.Transaction) bool {
1275+
return tx.Namespace == "ns1" && tx.Type == fftypes.TransactionTypeContractInvoke
1276+
})).Return(nil)
1277+
mdi.On("InsertOperation", mock.Anything, mock.MatchedBy(func(op *fftypes.Operation) bool {
1278+
return op.Namespace == "ns1" && op.Type == fftypes.OpTypeContractInvoke && op.Plugin == "mockblockchain"
1279+
})).Return(nil)
12381280
mbi.On("QueryContract", mock.Anything, req.Location, req.Method, req.Input).Return(struct{}{}, nil)
12391281

12401282
_, err := cm.InvokeContract(context.Background(), "ns1", req)
@@ -1245,6 +1287,7 @@ func TestQueryContract(t *testing.T) {
12451287
func TestCallContractInvalidType(t *testing.T) {
12461288
cm := newTestContractManager()
12471289
mim := cm.identity.(*identitymanagermocks.Manager)
1290+
mdi := cm.database.(*databasemocks.Plugin)
12481291

12491292
req := &fftypes.ContractCallRequest{
12501293
Interface: fftypes.NewUUID(),
@@ -1259,6 +1302,12 @@ func TestCallContractInvalidType(t *testing.T) {
12591302
}
12601303

12611304
mim.On("ResolveSigningKey", mock.Anything, "").Return("key-resolved", nil)
1305+
mdi.On("UpsertTransaction", mock.Anything, mock.MatchedBy(func(tx *fftypes.Transaction) bool {
1306+
return tx.Namespace == "ns1" && tx.Type == fftypes.TransactionTypeContractInvoke
1307+
})).Return(nil)
1308+
mdi.On("InsertOperation", mock.Anything, mock.MatchedBy(func(op *fftypes.Operation) bool {
1309+
return op.Namespace == "ns1" && op.Type == fftypes.OpTypeContractInvoke && op.Plugin == "mockblockchain"
1310+
})).Return(nil)
12621311

12631312
assert.PanicsWithValue(t, "unknown call type: ", func() {
12641313
cm.InvokeContract(context.Background(), "ns1", req)
@@ -1406,6 +1455,7 @@ func TestInvokeContractAPI(t *testing.T) {
14061455
mdb := cm.database.(*databasemocks.Plugin)
14071456
mim := cm.identity.(*identitymanagermocks.Manager)
14081457
mbi := cm.blockchain.(*blockchainmocks.Plugin)
1458+
mdi := cm.database.(*databasemocks.Plugin)
14091459

14101460
req := &fftypes.ContractCallRequest{
14111461
Type: fftypes.CallTypeInvoke,
@@ -1427,6 +1477,12 @@ func TestInvokeContractAPI(t *testing.T) {
14271477
mim.On("ResolveSigningKey", mock.Anything, "").Return("key-resolved", nil)
14281478
mdb.On("GetContractAPIByName", mock.Anything, "ns1", "banana").Return(api, nil)
14291479
mdb.On("GetFFIMethod", mock.Anything, "ns1", mock.Anything, mock.Anything).Return(&fftypes.FFIMethod{Name: "peel"}, nil)
1480+
mdi.On("UpsertTransaction", mock.Anything, mock.MatchedBy(func(tx *fftypes.Transaction) bool {
1481+
return tx.Namespace == "ns1" && tx.Type == fftypes.TransactionTypeContractInvoke
1482+
})).Return(nil)
1483+
mdi.On("InsertOperation", mock.Anything, mock.MatchedBy(func(op *fftypes.Operation) bool {
1484+
return op.Namespace == "ns1" && op.Type == fftypes.OpTypeContractInvoke && op.Plugin == "mockblockchain"
1485+
})).Return(nil)
14301486
mbi.On("InvokeContract", mock.Anything, mock.AnythingOfType("*fftypes.UUID"), "key-resolved", req.Location, mock.AnythingOfType("*fftypes.FFIMethod"), req.Input).Return(struct{}{}, nil)
14311487

14321488
_, err := cm.InvokeContractAPI(context.Background(), "ns1", "banana", "peel", req)

pkg/fftypes/operation.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2021 Kaleido, Inc.
1+
// Copyright © 2022 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -36,6 +36,8 @@ var (
3636
OpTypeTokenAnnouncePool OpType = ffEnum("optype", "token_announce_pool")
3737
// OpTypeTokenTransfer is a token transfer
3838
OpTypeTokenTransfer OpType = ffEnum("optype", "token_transfer")
39+
// OpTypeContractInvoke is a smart contract invoke
40+
OpTypeContractInvoke OpType = ffEnum("optype", "contract_invoke")
3941
)
4042

4143
// OpStatus is the current status of an operation

pkg/fftypes/transaction.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ var (
2727
TransactionTypeTokenPool TransactionType = ffEnum("txtype", "token_pool")
2828
// TransactionTypeTokenTransfer represents a token transfer
2929
TransactionTypeTokenTransfer TransactionType = ffEnum("txtype", "token_transfer")
30+
// TransactionTypeContractInvoke is a smart contract invoke
31+
TransactionTypeContractInvoke OpType = ffEnum("txtype", "contract_invoke")
3032
)
3133

3234
// TransactionRef refers to a transaction, in other types

0 commit comments

Comments
 (0)