Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Centrifuge chain NFT #1469

Merged
merged 12 commits into from
Mar 22, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ jobs:
run: |
if [ "${MATRIX_TEST}" != "unit" ]; then
[[ -s ${HOME}/.nvm/nvm.sh ]] && . ${HOME}/.nvm/nvm.sh # This loads NVM
nvm install 10.15.1
nvm alias default 10.15.1
npm install -g [email protected]
sh <(curl -L https://nixos.org/nix/install) --darwin-use-unencrypted-nix-store-volume
. ${HOME}/.nix-profile/etc/profile.d/nix.sh
nix-env -iA cachix -f https://cachix.org/api/v1/install
cachix use dapp
git clone --recursive https://github.com/dapphub/dapptools ${HOME}/.dapp/dapptools
bash -c "cd ${HOME}/.dapp/dapptools && git checkout b76035185e67be430d851af81ad62c5f42c3e965"
nix-env -f ${HOME}/.dapp/dapptools -iA dapp seth solc
nvm install 10.15.1 &> /dev/null
nvm alias default 10.15.1 &> /dev/null
npm install -g [email protected] &> /dev/null
sh <(curl -L https://nixos.org/nix/install) --darwin-use-unencrypted-nix-store-volume &> /dev/null
. ${HOME}/.nix-profile/etc/profile.d/nix.sh &> /dev/null
nix-env -iA cachix -f https://cachix.org/api/v1/install &> /dev/null
cachix use dapp &> /dev/null
git clone --recursive https://github.com/dapphub/dapptools ${HOME}/.dapp/dapptools &> /dev/null
bash -c "cd ${HOME}/.dapp/dapptools && git checkout b76035185e67be430d851af81ad62c5f42c3e965" &> /dev/null
nix-env -f ${HOME}/.dapp/dapptools -iA dapp seth solc &> /dev/null
fi
make install-deps
make install-deps &> /dev/null
test=${{ matrix.test }} make run-tests
- name: Upload coverage
run: bash <(curl -s https://codecov.io/bash)
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ clean: ##clean all dev contracts in build folder
@rm -rf build/chainbridge-deploy/cb-sol-cli/chainbridge-solidity
@rm -rf build/ethereum-bridge-contracts/out
@rm -rf build/privacy-enabled-erc721/out
@rm -f localAddresses
@rm -f profile.out
@rm -f coverage.txt

install-deps: ## Install Dependencies
@go mod tidy
Expand Down
4 changes: 2 additions & 2 deletions anchors/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (s *service) PreCommitAnchor(ctx context.Context, anchorID AnchorID, signin
return err
}

err = s.api.SubmitAndWatch(ctx, meta, c, krp)
_, err = s.api.SubmitAndWatch(ctx, meta, c, krp)
if err != nil {
return fmt.Errorf("failed to precommit document: %w", err)
}
Expand Down Expand Up @@ -130,7 +130,7 @@ func (s *service) CommitAnchor(ctx context.Context, anchorID AnchorID, documentR
return err
}

err = s.api.SubmitAndWatch(ctx, meta, c, krp)
_, err = s.api.SubmitAndWatch(ctx, meta, c, krp)
if err != nil {
return fmt.Errorf("failed to commit document: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion build/configs/default_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ ethereum:
gasLimits:
idCreate: 1000000
idAddKey: 300000
idRevokeKey: 55000
idRevokeKey: 85000
anchorCommit: 85000
anchorPreCommit: 100000
nftMint: 900000
Expand Down
2 changes: 1 addition & 1 deletion build/scripts/docker/docker-compose-bridge.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '3'
services:
bridge:
image: "centrifugeio/chainbridge:20201210171038-58034cb"
image: "centrifugeio/chainbridge:2021031218-6e5bbcf"
container_name: bridge
environment:
- KEYSTORE_PASSWORD=centrifuge
Expand Down
2 changes: 1 addition & 1 deletion build/scripts/test-dependencies/bridge/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ echo "MaxCount: $maxCount"
count=0
while true
do
started=`docker logs bridge 2>&1 | grep 'Started'`
started=$(docker logs bridge 2>&1 | grep 'Block not ready, will retry')
if [ "$started" != "" ]; then
echo "Bridge successfully started"
break
Expand Down
8 changes: 5 additions & 3 deletions build/scripts/test_wrapper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ if $MIGRATE; then
############################################################

################# Migrate contracts ########################
${PARENT_DIR}/build/scripts/migrate.sh
rm -f /tmp/migration.log
"${PARENT_DIR}"/build/scripts/migrate.sh &> /tmp/migration.log
if [ $? -ne 0 ]; then
echo "migrations failed"
cat /tmp/migration.log
exit 1
fi

rm -f /tmp/migration.log
## adding this env here as well since the envs from previous step(child script) is not imported
export MIGRATION_RAN=true

Expand Down Expand Up @@ -97,7 +99,7 @@ if $MIGRATE; then
if [ -n "${CC_DOCKER_CONTAINER_WAS_RUNNING}" ]; then
echo "Container ${CC_DOCKER_CONTAINER_NAME} was already running before the test setup. Not tearing it down as the assumption is that the container was started outside this context."
else
echo "Bringing Centtrifuge Chain down"
echo "Bringing Centrifuge Chain down"
docker rm -f cc-node
fi

Expand Down
102 changes: 77 additions & 25 deletions centchain/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package centchain

import (
"context"
"encoding/gob"
"fmt"
"strings"
"sync"
Expand Down Expand Up @@ -33,8 +34,28 @@ const (
ErrInvalidTransaction = errors.Error("Invalid Transaction")
)

func init() {
gob.Register(ExtrinsicInfo{})
}

var log = logging.Logger("centchain-client")

// ExtrinsicInfo holds details of a successful extrinsic
type ExtrinsicInfo struct {
Hash types.Hash
BlockHash types.Hash
Index uint // index number of extrinsic in a block

// EventsRaw contains all the events in the given block
// if you want to filter events for an extrinsic, use the Index
EventsRaw types.EventRecordsRaw
}

// Events returns all the events occurred in a given block
func (e ExtrinsicInfo) Events(meta *types.Metadata) (events Events, err error) {
return events, e.EventsRaw.DecodeEventRecords(meta, &events)
}

// API exposes required functions to interact with Centrifuge Chain.
type API interface {

Expand All @@ -49,7 +70,11 @@ type API interface {
SubmitExtrinsic(ctx context.Context, meta *types.Metadata, c types.Call, krp signature.KeyringPair) (txHash types.Hash, bn types.BlockNumber, sig types.MultiSignature, err error)

// SubmitAndWatch returns function that submits and watches an extrinsic, implements transaction.Submitter
SubmitAndWatch(ctx context.Context, meta *types.Metadata, c types.Call, krp signature.KeyringPair) error
SubmitAndWatch(
ctx context.Context, meta *types.Metadata, c types.Call, krp signature.KeyringPair) (ExtrinsicInfo, error)

// GetStorageLatest returns latest value at the given key
GetStorageLatest(key types.StorageKey, target interface{}) error
}

// substrateAPI exposes Substrate API functions
Expand Down Expand Up @@ -141,6 +166,10 @@ func (a *api) GetMetadataLatest() (*types.Metadata, error) {
return a.sapi.GetMetadataLatest()
}

func (a *api) GetStorageLatest(key types.StorageKey, target interface{}) error {
return a.sapi.GetStorageLatest(key, target)
}

func (a *api) submitExtrinsic(c types.Call, nonce uint64, krp signature.KeyringPair) (txHash types.Hash,
bn types.BlockNumber, sig types.MultiSignature, err error) {
ext := types.NewExtrinsic(c)
Expand Down Expand Up @@ -234,24 +263,26 @@ func (a *api) SubmitExtrinsic(ctx context.Context, meta *types.Metadata, c types
}

// SubmitAndWatch is submitting a CentChain transaction and starts a task to wait for the transaction result
func (a *api) SubmitAndWatch(ctx context.Context, meta *types.Metadata, c types.Call, krp signature.KeyringPair) error {
func (a *api) SubmitAndWatch(
ctx context.Context, meta *types.Metadata, c types.Call, krp signature.KeyringPair) (info ExtrinsicInfo,
err error) {
did, err := contextutil.AccountDID(ctx)
if err != nil {
return fmt.Errorf("failed to get DID: %w", err)
return info, fmt.Errorf("failed to get DID: %w", err)
}

txHash, bn, sig, err := a.SubmitExtrinsic(ctx, meta, c, krp)
if err != nil {
return fmt.Errorf("failed to submit extrinsic: %w", err)
return info, fmt.Errorf("failed to submit extrinsic: %w", err)
}

s, err := getSignature(sig)
if err != nil {
return fmt.Errorf("failed to get signature: %w", err)
return info, fmt.Errorf("failed to get signature: %w", err)
}

task := fmt.Sprintf("cent_chain_tx_status-%s", txHash.Hex())
a.dispatcher.RegisterRunnerFunc(task, func([]interface{}, map[string]interface{}) (interface{}, error) {
a.dispatcher.RegisterRunnerFunc(task, func([]interface{}, map[string]interface{}) (result interface{}, err error) {
bh, err := a.sapi.GetBlockHash(uint64(bn))
if err != nil {
return nil, fmt.Errorf("failed to get block hash: %w", err)
Expand All @@ -263,23 +294,38 @@ func (a *api) SubmitAndWatch(ctx context.Context, meta *types.Metadata, c types.
}

extIdx := isExtrinsicSignatureInBlock(s, block.Block)
if extIdx == -1 {
if extIdx < 0 {
log.Debugf("Extrinsic %s not found in block %d, trying in next block...", txHash.Hex(), bn)
bn++
return nil, fmt.Errorf("extrinsic %s not found in block %d", txHash.Hex(), bn)
}

return nil, checkExtrinsicEventSuccess(meta, a.sapi, bh, extIdx)
eventsRaw, err := checkExtrinsicEventSuccess(meta, a.sapi, bh, extIdx)
if err != nil {
return nil, err
}

info := ExtrinsicInfo{
Hash: txHash,
BlockHash: bh,
Index: uint(extIdx),
EventsRaw: eventsRaw,
}
return info, nil
})

job := gocelery.NewRunnerFuncJob("", task, nil, nil, time.Time{})
res, err := a.dispatcher.Dispatch(did, job)
if err != nil {
return fmt.Errorf("failed to dispatch job: %w", err)
return info, fmt.Errorf("failed to dispatch job: %w", err)
}

_, err = res.Await(context.Background())
return err
result, err := res.Await(context.Background())
if err != nil {
return info, err
}

return result.(ExtrinsicInfo), nil
}

func (a *api) incrementNonce(accountID []byte) {
Expand Down Expand Up @@ -334,45 +380,51 @@ func getSignature(msig types.MultiSignature) (types.Signature, error) {
func isExtrinsicSignatureInBlock(extSign types.Signature, block types.Block) int {
found := -1
for idx, xx := range block.Extrinsics {
if xx.Signature.Signature.AsSr25519 == extSign {
if xx.Signature.Signature.IsSr25519 && xx.Signature.Signature.AsSr25519 == extSign {
found = idx
break
}

if xx.Signature.Signature.IsEd25519 && xx.Signature.Signature.AsEd25519 == extSign {
found = idx
break
}
}
return found
}

func checkExtrinsicEventSuccess(meta *types.Metadata, api substrateAPI, blockHash types.Hash, extrinsicIdx int) error {
func checkExtrinsicEventSuccess(meta *types.Metadata, api substrateAPI, blockHash types.Hash,
extrinsicIdx int) (eventsRaw types.EventRecordsRaw, err error) {
key, err := types.CreateStorageKey(meta, "System", "Events", nil, nil)
if err != nil {
return err
return eventsRaw, err
}

var er types.EventRecordsRaw
err = api.GetStorage(key, &er, blockHash)
err = api.GetStorage(key, &eventsRaw, blockHash)
if err != nil {
return err
return eventsRaw, err
}

e := Events{}
err = er.DecodeEventRecords(meta, &e)
events := Events{}
err = eventsRaw.DecodeEventRecords(meta, &events)
if err != nil {
return err
return eventsRaw, err
}

// Check success events
for _, es := range e.System_ExtrinsicSuccess {
for _, es := range events.System_ExtrinsicSuccess {
if es.Phase.IsApplyExtrinsic && es.Phase.AsApplyExtrinsic == uint32(extrinsicIdx) {
return nil // Success executing extrinsic
return eventsRaw, nil // Success executing extrinsic
}
}

// Otherwise, check failure events
for _, es := range e.System_ExtrinsicFailed {
for _, es := range events.System_ExtrinsicFailed {
if es.Phase.IsApplyExtrinsic && es.Phase.AsApplyExtrinsic == uint32(extrinsicIdx) {
return errors.New("extrinsic %d failed %v", extrinsicIdx, es.DispatchError) // Failure executing extrinsic
return eventsRaw, errors.New("extrinsic %d failed %v", extrinsicIdx,
es.DispatchError) // Failure executing extrinsic
}
}

return errors.New("should not have reached this step: %v", e)
return eventsRaw, errors.New("should not have reached this step: %v", events)
}
65 changes: 65 additions & 0 deletions centchain/api_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// +build integration

package centchain_test

import (
"context"
"os"
"sync"
"testing"

"github.com/centrifuge/go-centrifuge/bootstrap"
cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap"
"github.com/centrifuge/go-centrifuge/centchain"
"github.com/centrifuge/go-centrifuge/config"
"github.com/centrifuge/go-centrifuge/contextutil"
"github.com/centrifuge/go-centrifuge/jobs"
"github.com/centrifuge/go-substrate-rpc-client/v2/types"
"github.com/stretchr/testify/assert"
)

var api centchain.API
var cfg config.Configuration
var cfgSrv config.Service

func TestMain(m *testing.M) {
ctx := cc.TestFunctionalEthereumBootstrap()
api = ctx[centchain.BootstrappedCentChainClient].(centchain.API)
dispatcher := ctx[jobs.BootstrappedDispatcher].(jobs.Dispatcher)
cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration)
cfgSrv = ctx[config.BootstrappedConfigStorage].(config.Service)
ctxh, canc := context.WithCancel(context.Background())
wg := new(sync.WaitGroup)
wg.Add(1)
go dispatcher.Start(ctxh, wg, nil)
result := m.Run()
cc.TestFunctionalEthereumTearDown()
canc()
wg.Wait()
os.Exit(result)
}

func TestApi_SubmitAndWatch(t *testing.T) {
meta, err := api.GetMetadataLatest()
assert.NoError(t, err)

call, err := types.NewCall(meta, "System.remark", []byte{})
assert.NoError(t, err)

id, err := cfg.GetIdentityID()
assert.NoError(t, err)

acc, err := cfgSrv.GetAccount(id)
assert.NoError(t, err)

caa := acc.GetCentChainAccount()
kr, err := caa.KeyRingPair()
assert.NoError(t, err)

info, err := api.SubmitAndWatch(contextutil.WithAccount(context.Background(), acc), meta, call, kr)
assert.NoError(t, err)

events, err := info.Events(meta)
assert.NoError(t, err)
assert.True(t, len(events.System_ExtrinsicSuccess) > 1)
}
Loading