A very experimental PLC implementation which uses BFT consensus for decentralization
at main 2.6 kB view raw
1package abciapp 2 3import ( 4 "context" 5 "encoding/json" 6 7 "github.com/did-method-plc/go-didplc" 8 cbornode "github.com/ipfs/go-ipld-cbor" 9 "github.com/palantir/stacktrace" 10 "tangled.org/gbl08ma.com/didplcbft/plc" 11) 12 13var TransactionActionCreatePlcOp = registerTransactionAction[CreatePlcOpArguments]("CreatePlcOp", processCreatePlcOpTx) 14 15type CreatePlcOpArguments struct { 16 DID string `json:"did" refmt:"did"` 17 Operation *didplc.OpEnum `refmt:"operation"` 18} 19 20func (CreatePlcOpArguments) ForAction() TransactionAction { 21 return TransactionActionCreatePlcOp 22} 23 24func init() { 25 cbornode.RegisterCborType(CreatePlcOpArguments{}) 26 cbornode.RegisterCborType(Transaction[CreatePlcOpArguments]{}) 27} 28 29func processCreatePlcOpTx(ctx context.Context, deps TransactionProcessorDependencies, txBytes []byte) (*processResult, error) { 30 tx, err := UnmarshalTransaction[CreatePlcOpArguments](txBytes) 31 if err != nil { 32 return &processResult{ 33 Code: 4000, 34 Info: err.Error(), 35 }, nil 36 } 37 38 // sadly didplc is really designed to unmarshal JSON, not CBOR 39 // so JSON ends up being the lingua franca for operations inside our PLC implementation too 40 // we also can't instance didplc.Operations directly from the CBOR unmarshaller (the MakeUnmarshalTransformFunc thing) 41 // because the interface makes us lose data (it is not powerful enough to detect the type of a transaction, for instance) 42 // so our PLC internals end up depending on OpEnum, too 43 // the decision to use CBOR for the entire thing at the blockchain transaction level is: 44 // - to make transactions more compact 45 // - to have more of a canonical format for them (we specifically use the stable CBOR format already used by the PLC for signing) 46 47 // there is one advantage to this approach: by ensuring we first unmarshal the operations into strongly defined types 48 // (e.g. the OpEnum struct of the didplc package) 49 // we avoid accepting malformed data like what happened in https://github.com/did-method-plc/did-method-plc/issues/71 50 opBytes, err := json.Marshal(tx.Arguments.Operation) 51 if err != nil { 52 return nil, stacktrace.Propagate(err, "internal error") 53 } 54 55 if writeTx, ok := deps.writeTx.Get(); ok { 56 err = deps.plc.ExecuteOperation(ctx, writeTx, tx.Arguments.DID, opBytes) 57 } else { 58 err = deps.plc.ValidateOperation(ctx, deps.readTx, tx.Arguments.DID, opBytes) 59 } 60 if err != nil { 61 if code, ok := plc.InvalidOperationErrorCode(err); ok { 62 return &processResult{ 63 Code: code, 64 Info: err.Error(), 65 }, nil 66 } 67 return nil, stacktrace.Propagate(err, "internal error") 68 } 69 70 return &processResult{ 71 Code: 0, 72 }, nil 73}