-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from singnet/master
Pull from parent
- Loading branch information
Showing
63 changed files
with
2,166 additions
and
380 deletions.
There are no files selected for viewing
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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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
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,233 @@ | ||
package blockchain | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/singnet/snet-daemon/config" | ||
"github.com/singnet/snet-daemon/ipfsutils" | ||
log "github.com/sirupsen/logrus" | ||
"math/big" | ||
"strings" | ||
"time" | ||
) | ||
|
||
/* | ||
This metadata structure defines the organization to group mappings. | ||
Please note , that groups are logical bucketing of managing payments ( same recipient for each group across the services in an organization) | ||
A given Organization will be associated with multiple groups and every group will be associated to a payment | ||
Sample example of the JSON structure from the block chain is given below . | ||
Please note that all the services that belong to a given group in an organization will have the same recipient address. | ||
*/ | ||
|
||
/* | ||
{ | ||
"org_name": "organization_name", | ||
"org_id": "org_id1", | ||
"groups": [ | ||
{ | ||
"group_name": "default_group2", | ||
"group_id": "99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=", | ||
"payment": { | ||
"payment_address": "0x671276c61943A35D5F230d076bDFd91B0c47bF09", | ||
"payment_expiration_threshold": 40320, | ||
"payment_channel_storage_type": "etcd", | ||
"payment_channel_storage_client": { | ||
"connection_timeout": "5s", | ||
"request_timeout": "3s", | ||
"endpoints": [ | ||
"http://127.0.0.1:2379" | ||
] | ||
} | ||
} | ||
}, | ||
{ | ||
"group_name": "default_group2", | ||
"group_id": "99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=", | ||
"payment": { | ||
"payment_address": "0x671276c61943A35D5F230d076bDFd91B0c47bF09", | ||
"payment_expiration_threshold": 40320, | ||
"payment_channel_storage_type": "etcd", | ||
"payment_channel_storage_client": { | ||
"connection_timeout": "5s", | ||
"request_timeout": "3s", | ||
"endpoints": [ | ||
"http://127.0.0.1:2379" | ||
] | ||
} | ||
} | ||
} | ||
] | ||
}*/ | ||
|
||
type OrganizationMetaData struct { | ||
OrgName string `json:"org_name"` | ||
OrgID string `json:"org_id"` | ||
Groups []Group `json:"groups"` | ||
//This will used to determine which group the daemon belongs to | ||
daemonGroup *Group | ||
daemonGroupID [32]byte | ||
recipientPaymentAddress common.Address | ||
} | ||
|
||
type Payment struct { | ||
PaymentAddress string `json:"payment_address"` | ||
PaymentExpirationThreshold *big.Int `json:"payment_expiration_threshold"` | ||
PaymentChannelStorageType string `json:"payment_channel_storage_type"` | ||
PaymentChannelStorageClient PaymentChannelStorageClient `json:"payment_channel_storage_client"` | ||
} | ||
|
||
//Structure to hold the individual group details , an Organization can have multiple groups | ||
type Group struct { | ||
GroupName string `json:"group_name"` | ||
GroupID string `json:"group_id"` | ||
PaymentDetails Payment `json:"payment"` | ||
} | ||
|
||
//Structure to hold the storage details of the payment | ||
type PaymentChannelStorageClient struct { | ||
ConnectionTimeout string `json:"connection_timeout" mapstructure:"connection_timeout"` | ||
RequestTimeout string `json:"request_timeout" mapstructure:"request_timeout"` | ||
Endpoints []string `json:"endpoints"` | ||
} | ||
|
||
//Construct the Organization metadata from the JSON Passed | ||
func InitOrganizationMetaDataFromJson(jsonData string) (metaData *OrganizationMetaData, err error) { | ||
metaData = new(OrganizationMetaData) | ||
err = json.Unmarshal([]byte(jsonData), &metaData) | ||
if err != nil { | ||
log.WithError(err).WithField("jsondata", jsonData) | ||
return nil, err | ||
} | ||
|
||
//Check for mandatory validations | ||
|
||
if err = setDerivedAttributes(metaData); err != nil { | ||
log.WithError(err) | ||
return nil, err | ||
} | ||
if err = checkMandatoryFields(metaData); err != nil { | ||
return nil,err | ||
} | ||
|
||
return metaData, nil | ||
} | ||
|
||
func checkMandatoryFields(metaData *OrganizationMetaData) (err error ){ | ||
if metaData.daemonGroup.PaymentDetails.PaymentChannelStorageClient.Endpoints == nil { | ||
err = fmt.Errorf("Mandatory field : ETCD Client Endpoints are mising for the Group %v ",metaData.daemonGroup.GroupName) | ||
} | ||
if &metaData.recipientPaymentAddress == nil { | ||
err = fmt.Errorf("Mandatory field : Recepient Address is missing for the Group %v ",metaData.daemonGroup.GroupName) | ||
} | ||
return | ||
} | ||
|
||
func setDerivedAttributes(metaData *OrganizationMetaData) (err error) { | ||
if metaData.daemonGroup, err = getDaemonGroup(*metaData); err != nil { | ||
return err | ||
} | ||
metaData.daemonGroupID, err = ConvertBase64Encoding(metaData.daemonGroup.GroupID) | ||
//use the checksum address ( convert the address in to a checksum address and set it back) | ||
metaData.daemonGroup.PaymentDetails.PaymentAddress = ToChecksumAddress(metaData.daemonGroup.PaymentDetails.PaymentAddress) | ||
|
||
metaData.recipientPaymentAddress = common.HexToAddress(metaData.daemonGroup.PaymentDetails.PaymentAddress) | ||
|
||
return err | ||
} | ||
|
||
//Determine the group this Daemon belongs to | ||
func getDaemonGroup(metaData OrganizationMetaData) (group *Group, err error) { | ||
groupName := config.GetString(config.DaemonGroupName) | ||
for _, group := range metaData.Groups { | ||
if strings.Compare(group.GroupName, groupName) == 0 { | ||
return &group, nil | ||
} | ||
} | ||
err = fmt.Errorf("group name %v in config is invalid, "+ | ||
"there was no group found with this name in the metadata", groupName) | ||
log.WithError(err) | ||
return nil, err | ||
} | ||
|
||
//Will be used to load the Organization metadata when Daemon starts | ||
//To be part of components | ||
func GetOrganizationMetaData() *OrganizationMetaData { | ||
var metadata *OrganizationMetaData | ||
var err error | ||
if config.GetBool(config.BlockchainEnabledKey) { | ||
ipfsHash := string(getMetaDataURI()) | ||
metadata, err = GetOrganizationMetaDataFromIPFS(FormatHash(ipfsHash)) | ||
} else { | ||
metadata = &OrganizationMetaData{daemonGroup:&Group{}} | ||
} | ||
if err != nil { | ||
log.WithError(err). | ||
Panic("error on retrieving / parsing organization metadata from block chain") | ||
} | ||
return metadata | ||
} | ||
|
||
func GetOrganizationMetaDataFromIPFS(hash string) (*OrganizationMetaData, error) { | ||
jsondata := ipfsutils.GetIpfsFile(hash) | ||
return InitOrganizationMetaDataFromJson(jsondata) | ||
} | ||
|
||
|
||
func getMetaDataURI() []byte { | ||
//Block chain call here to get the hash of the metadata for the given Organization | ||
reg := getRegistryCaller() | ||
orgId := StringToBytes32(config.GetString(config.OrganizationId)) | ||
|
||
organizationRegistered, err := reg.GetOrganizationById(nil, orgId) | ||
if err != nil || !organizationRegistered.Found { | ||
log.WithError(err).WithField("OrganizationId", config.GetString(config.OrganizationId)). | ||
Panic("Error Retrieving contract details for the Given Organization") | ||
} | ||
return organizationRegistered.OrgMetadataURI[:] | ||
} | ||
|
||
//Get the Group ID the Daemon needs to associate itself to , requests belonging to a different group if will be rejected | ||
func (metaData OrganizationMetaData) GetGroupIdString() string { | ||
return metaData.daemonGroup.GroupID | ||
} | ||
|
||
// Return the group id in bytes | ||
func (metaData OrganizationMetaData) GetGroupId() [32]byte { | ||
return metaData.daemonGroupID | ||
} | ||
|
||
//Pass the group Name and retrieve the details of the payment address/ recipient address. | ||
func (metaData OrganizationMetaData) GetPaymentAddress() common.Address { | ||
return metaData.recipientPaymentAddress | ||
} | ||
|
||
//Payment expiration threshold | ||
func (metaData *OrganizationMetaData) GetPaymentExpirationThreshold() *big.Int { | ||
return metaData.daemonGroup.PaymentDetails.PaymentExpirationThreshold | ||
} | ||
|
||
//Get the End points of the Payment Storage used to update the storage state | ||
func (metaData OrganizationMetaData) GetPaymentStorageEndPoints() []string { | ||
return metaData.daemonGroup.PaymentDetails.PaymentChannelStorageClient.Endpoints | ||
} | ||
|
||
|
||
//Get the connection time out defined | ||
func (metaData OrganizationMetaData) GetConnectionTimeOut() ( connectionTimeOut time.Duration) { | ||
connectionTimeOut, err := time.ParseDuration(metaData.daemonGroup.PaymentDetails.PaymentChannelStorageClient.ConnectionTimeout); | ||
if err != nil { | ||
log.Errorf(err.Error()) | ||
} | ||
return connectionTimeOut | ||
} | ||
|
||
//Get the Request time out defined | ||
func (metaData OrganizationMetaData) GetRequestTimeOut() time.Duration { | ||
timeOut, err := time.ParseDuration(metaData.daemonGroup.PaymentDetails.PaymentChannelStorageClient.RequestTimeout); | ||
if err != nil { | ||
log.Errorf(err.Error()) | ||
} | ||
return timeOut | ||
} |
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,41 @@ | ||
package blockchain | ||
|
||
import ( | ||
"github.com/singnet/snet-daemon/config" | ||
"github.com/stretchr/testify/assert" | ||
"math/big" | ||
"testing" | ||
"time" | ||
) | ||
|
||
var testJsonOrgGroupData = "{ \"org_name\": \"organization_name\", \"org_id\": \"org_id1\", \"groups\": [ { \"group_name\": \"default_group2\", \"group_id\": \"99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=\", \"payment\": { \"payment_address\": \"0x671276c61943A35D5F230d076bDFd91B0c47bF09\", \"payment_expiration_threshold\": 40320, \"payment_channel_storage_type\": \"etcd\", \"payment_channel_storage_client\": { \"connection_timeout\": \"15s\", \"request_timeout\": \"13s\", \"endpoints\": [ \"http://127.0.0.1:2379\" ] } } }, { \"group_name\": \"default_group\", \"group_id\": \"99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=\", \"payment\": { \"payment_address\": \"0x671276c61943A35D5F230d076bDFd91B0c47bF09\", \"payment_expiration_threshold\": 40320, \"payment_channel_storage_type\": \"etcd\", \"payment_channel_storage_client\": { \"connection_timeout\": \"15s\", \"request_timeout\": \"13s\", \"endpoints\": [ \"http://127.0.0.1:2379\" ] } } } ] }" | ||
|
||
func TestGetOrganizationMetaData(t *testing.T) { | ||
metadata, err := InitOrganizationMetaDataFromJson(testJsonOrgGroupData) | ||
assert.Nil(t, err) | ||
assert.NotNil(t, metadata) | ||
assert.Equal(t, "organization_name", metadata.OrgName) | ||
address := metadata.GetPaymentAddress() | ||
assert.Equal(t, "0x671276c61943A35D5F230d076bDFd91B0c47bF09", address.Hex()) | ||
assert.Equal(t, "http://127.0.0.1:2379", metadata.GetPaymentStorageEndPoints()[0]) | ||
assert.Equal(t, "99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=", metadata.GetGroupIdString()) | ||
assert.Equal(t, big.NewInt(40320), metadata.GetPaymentExpirationThreshold()) | ||
grpId, _ := ConvertBase64Encoding("99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=") | ||
assert.Equal(t, grpId, metadata.GetGroupId()) | ||
assert.Equal(t, 15*time.Second, metadata.GetConnectionTimeOut()) | ||
assert.Equal(t, 13*time.Second, metadata.GetRequestTimeOut()) | ||
|
||
} | ||
|
||
func TestGetOrganizationMetaDataForError(t *testing.T) { | ||
metadata, err := InitOrganizationMetaDataFromJson("bad json") | ||
assert.Nil(t, metadata) | ||
assert.NotNil(t, err) | ||
|
||
config.Vip().Set(config.DaemonGroupName, "unknow") | ||
if metadata, err = InitOrganizationMetaDataFromJson(testJsonOrgGroupData); err != nil { | ||
assert.Nil(t, metadata) | ||
assert.Equal(t, "group name unknow in config is invalid, there was no group found with this name in the metadata", err.Error()) | ||
} | ||
config.Vip().Set(config.DaemonGroupName, "default_group") | ||
} |
Oops, something went wrong.