# Fabric Private Data PoC - Draft 1
## dependencies
- fabric v2 with implicit private collections
- hlf-proxy:1.7.0, endpoints: blocks, invoke y query
## chaincode
### model
object | storage | key pattern | key e.g. | value type | value e. g.
--- | --- | --- | --- | --- | ---
publicdoc | public | `{countrycode}:{docsubid}` | `AR:1234` | json | `{"version":1, "status":2}`
acl | public | `{doc.key}#acl` | `AR:1234#acl` | []string | `["BR", "PY"]`
event | public | `{doc.key}#event:{countrycode}:{eventsubid}` | `AR:1234#event:BR:0001` | json | `{"id":"AR:1234", "k1":"v1", "k2":"V2"}`
privatedoc | `_implicit_org_{MSPID}` | `{doc.key}#v{version}` | `AR:1234#v2` | json | `{"id":"AR:1234", "k1":"v1", "k2":"V2"}`
### function: AddEvent
param | mandatory | type | e.g.
--- | --- | --- | ---
arg1:docid | x | string | `AR:1234`
arg1:eventsubid | x | string | `1`, `2`
arg2:eventvalue | x | json | `{"eventtype":1,"docstatus":1,"date":"2021-11-01T14:10:23.Z000"}`
arg3:acl | | []string |`["BR", "PY"]`
trasient1:privatedoc | | json | `{"id":"AR:1234", "k1":"v1", "k2":"V2"}`
Rules:
- first event of new doc requires `privatedoc` (creation)
- only creator can to change `privatedoc`
- any event over an existing doc requires its `acl` contains signer
Flow:
```
publicdoc = shim.GetState(arg-docid)
currentacl = arg-acl
currentversion = 0
if publicdoc == null: // new doc
shim.PutState(docid, {version: currentversion, status: arg-eventvalue.status})
else: // doc already exists
if arg-acl == null: currentacl = shim.GetState(arg3-acl)
aclCheck with currentacl
if (arg-eventvalue.status != null and arg-eventvalue.status != publicdoc.docstatus)
or trasient-privatedoc != null:
if arg-eventvalue.status != null and arg-eventvalue.status != publicdoc.docstatus:
publicdoc.status = arg-eventvalue.docstatus
if transient-privatedoc != null:
currentversion = publicdoc.version + 1
else:
currentversion = publicdoc.version
shim.PutState(arg1:docid, {version: currentversion, status: arg-eventvalue.status})
shim.PutState(event)
if arg-acl != null: shim.PutState(arg-acl)
if transient-privatedoc != null
for owner and each org in currentacl
shim.PutPrivateData(_implicit_org_{MSPID}, {arg-docid}#v{currentversion}, transient-privatedoc)
```
## using hlf-proxy
### model
- to copy all ledger into dababase table (_"block-consumer style"_)
```
CREATE TABLE XXXX_STATE (
APPLICATION VARCHAR2, // e. g. SINTIA
BLOCK INTEGER,
TX_ID VARCHAR2(100),
TX_TIMESTAMP DATE,
KEY VARCHAR2(100),
VALUE VARCHAR2(4000)
);
```
- to copy private doc
```
CREATE TABLE XXX_PRIVATE_DOC
TX_ID VARCHAR2(100),
DOC_ID VARCHAR(100),
DOC_VERSION INTEGER(3),
DOC_CONTENT CLOB
)
```
### Flow
```
newblock = GET hlf-proxy endpoint `blocks/{channel}/{blockNumber}?validTxsOnly`
for each tx in newblock:
if tx.chaincode == XXX and tx.function == 'AddEvent' and writeSet.size > 0:
// Copy all ledger
for item on tx.writeSet: db.saveWriteSet( newblock.block, tx.txid, ..., item.key, item.value )
// trying to recover private data
docid = getDocidFromKey(tx.writeSet.item[0].key)
publicdoc = filterPublicdocFromWriteSet(tx.writeSet)
savedVersion = db.selectPrivatedocVersion(docid)
if publicdoc != null
and (savedVersion == null or savedVersion != publicdoc.version)
pk = docid+'#v'+publicdoc.version
privatedoc = POST hlf-proxy "query/{channel}/XXX" body {function:"GetPrivatedoc", args:[pk]}
if OK // httpStatusCode 200
db.savePrivatedoc( tx.txid, docid, publicdoc.version, privatedoc )
```