// getAccountIDsFromAttribute retrieves account IDs stored in TCert attributes // cert: TCert to read account IDs from // attributeNames: attribute names inside TCert that stores the entity's account IDs func (t *certHandler) getAccountIDsFromAttribute(cert []byte, attributeNames []string) ([]string, error) { if cert == nil || attributeNames == nil { return nil, errors.New("cert or accountIDs list is empty") } //decleare return object (slice of account IDs) var acctIds []string // for each attribute name, look for that attribute name inside TCert, // the correspounding value of that attribute is the account ID for _, attributeName := range attributeNames { myLogger.Debugf("get value from attribute = v%", attributeName) //get the attribute value from the corresbonding attribute name accountID, err := attr.GetValueFrom(attributeName, cert) if err != nil { myLogger.Errorf("system error %v", err) return nil, errors.New("unable to find user contact information") } acctIds = append(acctIds, string(accountID)) } myLogger.Debugf("ids = %v", acctIds) return acctIds, nil }
func (t *AssetManagementChaincode) assign(stub *shim.ChaincodeStub, args []string) ([]byte, error) { fmt.Println("Assigning Asset...") if len(args) != 2 { return nil, errors.New("Incorrect number of arguments. Expecting 2") } asset := args[0] owner, err := base64.StdEncoding.DecodeString(args[1]) if err != nil { fmt.Printf("Error decoding [%v] \n", err) return nil, errors.New("Failed decodinf owner") } // Recover the role that is allowed to make assignments assignerRole, err := stub.GetState("assignerRole") if err != nil { fmt.Printf("Error getting role [%v] \n", err) return nil, errors.New("Failed fetching assigner role") } callerRole, err := stub.ReadCertAttribute("role") if err != nil { fmt.Printf("Error reading attribute [%v] \n", err) return nil, fmt.Errorf("Failed fetching caller role. Error was [%v]", err) } caller := string(callerRole[:]) assigner := string(assignerRole[:]) if caller != assigner { fmt.Printf("Caller is not assigner - caller %v assigner %v\n", caller, assigner) return nil, fmt.Errorf("The caller does not have the rights to invoke assign. Expected role [%v], caller role [%v]", assigner, caller) } account, err := attr.GetValueFrom("account", owner) if err != nil { fmt.Printf("Error reading account [%v] \n", err) return nil, fmt.Errorf("Failed fetching recipient account. Error was [%v]", err) } // Register assignment myLogger.Debugf("New owner of [%s] is [% x]", asset, owner) ok, err := stub.InsertRow("AssetsOwnership", shim.Row{ Columns: []*shim.Column{ &shim.Column{Value: &shim.Column_String_{String_: asset}}, &shim.Column{Value: &shim.Column_Bytes{Bytes: account}}}, }) if !ok && err == nil { fmt.Println("Error inserting row") return nil, errors.New("Asset was already assigned.") } return nil, err }
// getContactInfo retrieves the contact info stored as an attribute in a Tcert // cert: TCert func (t *certHandler) getContactInfo(cert []byte) (string, error) { if len(cert) == 0 { return "", errors.New("cert is empty") } contactInfo, err := attr.GetValueFrom(contactInfo, cert) if err != nil { myLogger.Errorf("system error %v", err) return "", errors.New("unable to find user contact information") } return string(contactInfo), err }
func (t *AssetManagementChaincode) transfer(stub *shim.ChaincodeStub, args []string) ([]byte, error) { if len(args) != 2 { return nil, errors.New("Incorrect number of arguments. Expecting 2") } asset := args[0] newOwner, err := base64.StdEncoding.DecodeString(args[1]) if err != nil { fmt.Printf("Error decoding [%v] \n", err) return nil, errors.New("Failed decoding owner") } // Verify the identity of the caller // Only the owner can transfer one of his assets var columns []shim.Column col1 := shim.Column{Value: &shim.Column_String_{String_: asset}} columns = append(columns, col1) row, err := stub.GetRow("AssetsOwnership", columns) if err != nil { return nil, fmt.Errorf("Failed retrieving asset [%s]: [%s]", asset, err) } prvOwner := row.Columns[1].GetBytes() myLogger.Debugf("Previous owener of [%s] is [% x]", asset, prvOwner) if len(prvOwner) == 0 { return nil, fmt.Errorf("Invalid previous owner. Nil") } // Verify ownership callerAccount, err := stub.ReadCertAttribute("account") if err != nil { return nil, fmt.Errorf("Failed fetching caller account. Error was [%v]", err) } if bytes.Compare(prvOwner, callerAccount) != 0 { return nil, fmt.Errorf("Failed verifying caller ownership.") } newOwnerAccount, err := attr.GetValueFrom("account", newOwner) if err != nil { return nil, fmt.Errorf("Failed fetching new owner account. Error was [%v]", err) } // At this point, the proof of ownership is valid, then register transfer err = stub.DeleteRow( "AssetsOwnership", []shim.Column{shim.Column{Value: &shim.Column_String_{String_: asset}}}, ) if err != nil { return nil, errors.New("Failed deliting row.") } _, err = stub.InsertRow( "AssetsOwnership", shim.Row{ Columns: []*shim.Column{ &shim.Column{Value: &shim.Column_String_{String_: asset}}, &shim.Column{Value: &shim.Column_Bytes{Bytes: newOwnerAccount}}, }, }) if err != nil { return nil, errors.New("Failed inserting row.") } return nil, nil }
func TestAssetManagement(t *testing.T) { // Administrator deploy the chaicode adminCert, err := administrator.GetTCertificateHandlerNext("role") if err != nil { t.Fatal(err) } if err := deploy(adminCert); err != nil { t.Fatal(err) } // Administrator assigns ownership of Picasso to Alice aliceCert, err := alice.GetTCertificateHandlerNext("role", "account") if err != nil { t.Fatal(err) } // This must fail if err := assignOwnership(alice, "Picasso", aliceCert); err == nil { t.Fatal("Alice doesn't have the assigner role. Assignment should fail.") } // This must succeed if err := assignOwnership(administrator, "Picasso", aliceCert); err != nil { t.Fatal(err) } // Check who is the owner of the Picasso theOnwerIs, err := whoIsTheOwner("Picasso") if err != nil { t.Fatal(err) } aliceAccount, err := attr.GetValueFrom("account", aliceCert.GetCertificate()) if !reflect.DeepEqual(theOnwerIs, aliceAccount) { fmt.Printf("%v --- %v", string(theOnwerIs), string(aliceAccount)) t.Fatal("Alice is not the owner of Picasso") } // Alice transfers ownership of Picasso to Bob bobCert, err := bob.GetTCertificateHandlerNext("role", "account") if err != nil { t.Fatal(err) } // This must fail if err := transferOwnership(bob, bobCert, "Picasso", adminCert); err == nil { t.Fatal(err) } // This must succeed if err := transferOwnership(alice, aliceCert, "Picasso", bobCert); err != nil { t.Fatal(err) } // Check who is the owner of the Picasso theOnwerIs, err = whoIsTheOwner("Picasso") if err != nil { t.Fatal(err) } bobAccount, err := attr.GetValueFrom("account", bobCert.GetCertificate()) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(theOnwerIs, bobAccount) { t.Fatal("Bob is not the owner of Picasso") } // Check who is the owner of an asset that doesn't exist _, err = whoIsTheOwner("Klee") if err == nil { t.Fatal("This asset doesn't exist. Querying should fail.") } }
//test the ability to transfer assets from owner account IDs to new owner account ID func TestAssetTransfer(t *testing.T) { //test transfer // create a new cert for alice used to transfer assets // (note this cert include multiple account Ids belong to alice) aliceCert, err := alice.GetTCertificateHandlerNext("role", "account1", "account2", "account3") if err != nil { t.Fatal(err) } // create a new cert for bob to recieve transfer from Alice // note "account2" is a new account ID that was never used before. Since this new account ID // will create a new record on the account ledger, you must also pass in all required parameters // required to create a new account record in chaincode state (such as user contact info) bobCert, err := bob.GetTCertificateHandlerNext("role", "account2", "contactInfo") if err != nil { t.Fatal(err) } //transfer 200 assets from Alice to Bob if nil != transferOwnership(alice, aliceCert, "account1,account2,account3", bobCert, "account2", "200") { t.Fatal(err) } /*********************** Codes below check if assets are correctly transfered, first find the actual account IDs from cert attributes, then call the getBalance method on the chaincode for each account ID ***********************/ // check that 200 assets have been transfered to Bob; first step is to collect account Ids aliceAccountID1, err := attr.GetValueFrom("account1", aliceCert.GetCertificate()) aliceAccountID2, err := attr.GetValueFrom("account2", aliceCert.GetCertificate()) aliceAccountID3, err := attr.GetValueFrom("account3", aliceCert.GetCertificate()) bobAccountID2, err := attr.GetValueFrom("account2", bobCert.GetCertificate()) //account1 of alice shouldn't have any balance left, and the account should have been //deleted from the asset depository alice1BalanceRaw, err := getBalance(string(aliceAccountID1)) fmt.Println("alice balance", alice1BalanceRaw) if alice1BalanceRaw != nil { t.Fatal(err) } fmt.Println("alice balance", alice1BalanceRaw) // account2 of alice should still have 100 left on its balance alice2BalanceRaw, err := getBalance(string(aliceAccountID2)) if err != nil { t.Fatal(err) } alicebalance2 := binary.BigEndian.Uint64(alice2BalanceRaw) if alicebalance2 != 100 { t.Fatal("retreived balance for account1 (alice) does not equal to 100") } // account3 of alice should still have 300 left on its balance alice3BalanceRaw, err := getBalance(string(aliceAccountID3)) if err != nil { t.Fatal(err) } alicebalance3 := binary.BigEndian.Uint64(alice3BalanceRaw) if alicebalance3 != 300 { t.Fatal("retreived balance for account1 (alice) does not equal to 300") } // account2 of bob should now have 200 on its balance bobBalanceRaw, err := getBalance(string(bobAccountID2)) if err != nil { t.Fatal(err) } bobbalance := binary.BigEndian.Uint64(bobBalanceRaw) if bobbalance != 200 { t.Fatal("retreived balance for account2 (bob) does not equal to 200") } }
// TestAssigningAssets the tests the ```assign``` method by making sure // authorized users (callers with 'issuer' role) can use the ```assign``` // method to allocate assets to its investors func TestAssigningAssets(t *testing.T) { // create certs carring account IDs for Alice and Bob aliceCert1, err := alice.GetTCertificateHandlerNext("role", "account1", "contactInfo") if err != nil { t.Fatal(err) } aliceCert2, err := alice.GetTCertificateHandlerNext("role", "account2", "contactInfo") if err != nil { t.Fatal(err) } aliceCert3, err := alice.GetTCertificateHandlerNext("role", "account3", "contactInfo") if err != nil { t.Fatal(err) } bobCert1, err := bob.GetTCertificateHandlerNext("role", "account1", "contactInfo") if err != nil { t.Fatal(err) } //issuer assign balances to assets to first batch of owners if err := assignOwnership(administrator, aliceCert1, "account1", "100"); err != nil { t.Fatal(err) } if err := assignOwnership(administrator, aliceCert2, "account2", "200"); err != nil { t.Fatal(err) } if err := assignOwnership(administrator, aliceCert3, "account3", "300"); err != nil { t.Fatal(err) } if err := assignOwnership(administrator, bobCert1, "account1", "1000"); err != nil { t.Fatal(err) } aliceAccountID1, err := attr.GetValueFrom("account1", aliceCert1.GetCertificate()) aliceAccountID2, err := attr.GetValueFrom("account2", aliceCert2.GetCertificate()) aliceAccountID3, err := attr.GetValueFrom("account3", aliceCert3.GetCertificate()) bobAccountID1, err := attr.GetValueFrom("account1", bobCert1.GetCertificate()) // Check if balances are assigned correctly alice1BalanceRaw, err := getBalance(string(aliceAccountID1)) if err != nil { t.Fatal(err) } alicebalance1 := binary.BigEndian.Uint64(alice1BalanceRaw) if alicebalance1 != 100 { t.Fatal("retreived balance does not equal to 100") } alice2BalanceRaw, err := getBalance(string(aliceAccountID2)) if err != nil { t.Fatal(err) } alicebalance2 := binary.BigEndian.Uint64(alice2BalanceRaw) if alicebalance2 != 200 { t.Fatal("retreived balance does not equal to 200") } alice3BalanceRaw, err := getBalance(string(aliceAccountID3)) if err != nil { t.Fatal(err) } alicebalance3 := binary.BigEndian.Uint64(alice3BalanceRaw) if alicebalance3 != 300 { t.Fatal("retreived balance does not equal to 300") } bob1BalanceRaw, err := getBalance(string(bobAccountID1)) if err != nil { t.Fatal(err) } bobbalance1 := binary.BigEndian.Uint64(bob1BalanceRaw) if bobbalance1 != 1000 { t.Fatal("retreived balance does not equal to 1000") } //check if contact info is correctly saved into the chaincode state ledger aliceContactInfo, err := getOwnerContactInformation(string(aliceAccountID1)) if err != nil { t.Fatal(err) } if string(aliceContactInfo) != "*****@*****.**" { t.Fatal("retreived contact info does not equal to [email protected]") } bobContactInfo, err := getOwnerContactInformation(string(bobAccountID1)) if err != nil { t.Fatal(err) } if string(bobContactInfo) != "*****@*****.**" { t.Fatal("retreived contact info does not equal to [email protected]") } }