-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Local CAS support for writing IPFS-compatible v0 CIDs
The local CAS is now capable of generating v0 CIDs that are compatible with an IPFS node, assuming that it's running under default settings and that the data is less than 256KB. However, this capability is not currently exposed or used outside of testing in order to ensure our current sample data doesn't break. In a future commit, the CID format (v0 or v1) will be determined dynamically based on the format of the data received by this Orb server from another Orb server. Signed-off-by: Derek Trider <[email protected]>
- Loading branch information
Derek Trider
committed
May 19, 2021
1 parent
4aca3a8
commit 99362af
Showing
7 changed files
with
839 additions
and
19 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
/* | ||
Copyright SecureKey Technologies Inc. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package cas | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
"time" | ||
|
||
"github.com/cenkalti/backoff/v4" | ||
ariesmemstorage "github.com/hyperledger/aries-framework-go/component/storageutil/mem" | ||
ipfsshell "github.com/ipfs/go-ipfs-api" | ||
dctest "github.com/ory/dockertest/v3" | ||
dc "github.com/ory/dockertest/v3/docker" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
const sampleAnchorCredential = `{ | ||
"@context": [ | ||
"https://www.w3.org/2018/credentials/v1", | ||
"https://trustbloc.github.io/did-method-orb/contexts/anchor/v1", | ||
"https://w3id.org/jws/v1" | ||
], | ||
"id": "http://sally.example.com/transactions/bafkreihwsnuregceqh263vgdathcprnbvatyat6h6mu7ipjhhodcdbyhoy", | ||
"type": [ | ||
"VerifiableCredential", | ||
"AnchorCredential" | ||
], | ||
"issuer": "https://sally.example.com/services/orb", | ||
"issuanceDate": "2021-01-27T09:30:10Z", | ||
"credentialSubject": { | ||
"operationCount": 1, | ||
"coreIndex": "bafkreihwsnuregceqh263vgdathcprnbvatyat6h6mu7ipjhhodcdbyhoy", | ||
"namespace": "did:orb", | ||
"version": "1", | ||
"previousAnchors": { | ||
"EiA329wd6Aj36YRmp7NGkeB5ADnVt8ARdMZMPzfXsjwTJA": "bafkreibmrmenuxhgaomod4m26ds5ztdujxzhjobgvpsyl2v2ndcskq2iay", | ||
"EiABk7KK58BVLHMataxgYZjTNbsHgtD8BtjF0tOWFV29rw": "bafkreibh3whnisud76knkv7z7ucbf3k2rs6knhvajernrdabdbfaomakli" | ||
}, | ||
"type": "Anchor" | ||
}, | ||
"proof": [{ | ||
"type": "JsonWebSignature2020", | ||
"proofPurpose": "assertionMethod", | ||
"created": "2021-01-27T09:30:00Z", | ||
"verificationMethod": "did:example:abcd#key", | ||
"domain": "sally.example.com", | ||
"jws": "eyJ..." | ||
}, | ||
{ | ||
"type": "JsonWebSignature2020", | ||
"proofPurpose": "assertionMethod", | ||
"created": "2021-01-27T09:30:05Z", | ||
"verificationMethod": "did:example:abcd#key", | ||
"domain": "https://witness1.example.com/ledgers/maple2021", | ||
"jws": "eyJ..." | ||
}, | ||
{ | ||
"type": "JsonWebSignature2020", | ||
"proofPurpose": "assertionMethod", | ||
"created": "2021-01-27T09:30:06Z", | ||
"verificationMethod": "did:example:efgh#key", | ||
"domain": "https://witness2.example.com/ledgers/spruce2021", | ||
"jws": "eyJ..." | ||
}] | ||
}` | ||
|
||
func TestEnsureLocalCASAndIPFSProduceSameCIDs(t *testing.T) { | ||
pool, ipfsResource := startIPFSDockerContainer(t) | ||
|
||
defer func() { | ||
require.NoError(t, pool.Purge(ipfsResource), "failed to purge IPFS resource") | ||
}() | ||
|
||
t.Run("v0", func(t *testing.T) { | ||
ensureCIDsAreEqualBetweenLocalCASAndIPFS(t, true) | ||
}) | ||
// TODO (#344) re-enable this test once the local CAS is capable of creating v1 CIDs. | ||
// t.Run("v1", func(t *testing.T) { | ||
// ensureCIDsAreEqualBetweenLocalCASAndIPFS(t, false) | ||
// }) | ||
} // nolint:wsl | ||
|
||
func startIPFSDockerContainer(t *testing.T) (*dctest.Pool, *dctest.Resource) { | ||
t.Helper() | ||
|
||
pool, err := dctest.NewPool("") | ||
require.NoError(t, err, "failed to create pool") | ||
|
||
ipfsResource, err := pool.RunWithOptions(&dctest.RunOptions{ | ||
Repository: "ipfs/go-ipfs", | ||
Tag: "master-2021-04-22-eea198f", | ||
PortBindings: map[dc.Port][]dc.PortBinding{ | ||
"5001/tcp": {{HostIP: "", HostPort: "5001"}}, | ||
}, | ||
}) | ||
if err != nil { | ||
require.FailNow(t, "Failed to start IPFS Docker image."+ | ||
" This can happen if there is an IPFS container still running from a previous unit test run."+ | ||
` Try "docker ps" from the command line and kill the old container if it's still running.`) | ||
} | ||
|
||
return pool, ipfsResource | ||
} | ||
|
||
func ensureCIDsAreEqualBetweenLocalCASAndIPFS(t *testing.T, useV0CIDs bool) { | ||
t.Helper() | ||
|
||
smallSimpleData := []byte("content") | ||
|
||
sampleAnchorCredentialBytes := []byte(sampleAnchorCredential) | ||
|
||
cidFromIPFS := addDataToIPFS(t, smallSimpleData, useV0CIDs) | ||
cidFromLocalCAS := addDataToLocalCAS(t, smallSimpleData, useV0CIDs) | ||
|
||
require.Equal(t, cidFromIPFS, cidFromLocalCAS) | ||
|
||
cidFromIPFS = addDataToIPFS(t, sampleAnchorCredentialBytes, useV0CIDs) | ||
cidFromLocalCAS = addDataToLocalCAS(t, sampleAnchorCredentialBytes, useV0CIDs) | ||
|
||
require.Equal(t, cidFromIPFS, cidFromLocalCAS) | ||
} | ||
|
||
func addDataToIPFS(t *testing.T, data []byte, useV0CIDs bool) string { | ||
t.Helper() | ||
|
||
shell := ipfsshell.NewShell("localhost:5001") | ||
|
||
shell.SetTimeout(2 * time.Second) | ||
|
||
// IPFS will need some time to start up, hence the need for retries. | ||
var cid string | ||
|
||
var v1AddOpt []ipfsshell.AddOpts | ||
|
||
if !useV0CIDs { | ||
v1AddOpt = []ipfsshell.AddOpts{ipfsshell.CidVersion(1)} | ||
} | ||
|
||
err := backoff.Retry(func() error { | ||
var err error | ||
cid, err = shell.Add(bytes.NewReader(data), v1AddOpt...) | ||
|
||
return err | ||
}, backoff.WithMaxRetries(backoff.NewConstantBackOff(time.Millisecond*500), 10)) | ||
require.NoError(t, err) | ||
|
||
return cid | ||
} | ||
|
||
func addDataToLocalCAS(t *testing.T, data []byte, useV0CIDs bool) string { | ||
t.Helper() | ||
|
||
cas, err := New(ariesmemstorage.NewProvider()) | ||
require.NoError(t, err) | ||
|
||
cas.useIPFSCompatibleV0CIDs = useV0CIDs | ||
|
||
cid, err := cas.Write(data) | ||
require.NoError(t, err) | ||
|
||
return cid | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.