Added migration method and cleaned things up.

This commit is contained in:
Mark Beamer Jr 2018-11-09 12:10:58 -05:00
parent dac2dbda61
commit ccd1b2b84d
No known key found for this signature in database
GPG key ID: 1C314FB89AD76973
4 changed files with 543 additions and 11 deletions

View file

@ -2,16 +2,18 @@ package claim
import ( import (
"encoding/hex" "encoding/hex"
"errors"
"github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/lbryio/lbry.go/errors"
"github.com/lbryio/lbryschema.go/address" "github.com/lbryio/lbryschema.go/address"
"github.com/lbryio/types/go" "github.com/lbryio/types/go"
) )
type ClaimHelper struct { type ClaimHelper struct {
*pb.Claim *pb.Claim
migratedFrom []byte
} }
func (c *ClaimHelper) ValidateAddresses(blockchainName string) error { func (c *ClaimHelper) ValidateAddresses(blockchainName string) error {
@ -21,7 +23,7 @@ func (c *ClaimHelper) ValidateAddresses(blockchainName string) error {
if fee != nil { if fee != nil {
tmp_addr := fee.GetAddress() tmp_addr := fee.GetAddress()
if len(tmp_addr) != 25 { if len(tmp_addr) != 25 {
return errors.New("invalid address length: " + string(len(tmp_addr)) + "!") return errors.Err("invalid address length: " + string(len(tmp_addr)) + "!")
} }
addr := [25]byte{} addr := [25]byte{}
for i := range addr { for i := range addr {
@ -29,7 +31,7 @@ func (c *ClaimHelper) ValidateAddresses(blockchainName string) error {
} }
_, err := address.EncodeAddress(addr, blockchainName) _, err := address.EncodeAddress(addr, blockchainName)
if err != nil { if err != nil {
return err return errors.Err(err)
} }
} }
} }
@ -44,20 +46,20 @@ func (c *ClaimHelper) ValidateCertificate() error {
keyType := certificate.GetKeyType() keyType := certificate.GetKeyType()
_, err := c.GetCertificatePublicKey() _, err := c.GetCertificatePublicKey()
if err != nil { if err != nil {
return err return errors.Err(err)
} }
if keyType.String() != SECP256k1 { if keyType.String() != SECP256k1 {
return errors.New("wrong curve: " + keyType.String()) return errors.Err("wrong curve: " + keyType.String())
} }
return nil return nil
} }
func (c *ClaimHelper) LoadFromBytes(raw_claim []byte, blockchainName string) error { func (c *ClaimHelper) LoadFromBytes(raw_claim []byte, blockchainName string) error {
if c.String() != "" { if c.String() != "" {
return errors.New("already initialized") return errors.Err("already initialized")
} }
if len(raw_claim) < 1 { if len(raw_claim) < 1 {
return errors.New("there is nothing to decode") return errors.Err("there is nothing to decode")
} }
claim_pb := &pb.Claim{} claim_pb := &pb.Claim{}
@ -65,7 +67,7 @@ func (c *ClaimHelper) LoadFromBytes(raw_claim []byte, blockchainName string) err
if err != nil { if err != nil {
return err return err
} }
*c = ClaimHelper{claim_pb} *c = ClaimHelper{claim_pb, raw_claim}
err = c.ValidateAddresses(blockchainName) err = c.ValidateAddresses(blockchainName)
if err != nil { if err != nil {
return err return err
@ -86,8 +88,8 @@ func (c *ClaimHelper) LoadFromHexString(claim_hex string, blockchainName string)
return c.LoadFromBytes(buf, blockchainName) return c.LoadFromBytes(buf, blockchainName)
} }
func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) { func DecodeClaimProtoBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
claim := &ClaimHelper{&pb.Claim{}} claim := &ClaimHelper{&pb.Claim{}, serialized}
err := claim.LoadFromBytes(serialized, blockchainName) err := claim.LoadFromBytes(serialized, blockchainName)
if err != nil { if err != nil {
return nil, err return nil, err
@ -109,7 +111,46 @@ func DecodeClaimJSON(claimJSON string, blockchainName string) (*ClaimHelper, err
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &ClaimHelper{c}, nil return &ClaimHelper{c, []byte(claimJSON)}, nil
}
// DecodeClaimBytes take a byte array and tries to decode it to a protobuf claim or migrate it from either json v1,2,3
func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
helper, err := DecodeClaimProtoBytes(serialized, blockchainName)
if err == nil {
return helper, nil
}
helper = &ClaimHelper{}
//If protobuf fails, try json versions before returning an error.
v1Claim := new(V1Claim)
err = v1Claim.Unmarshal(serialized)
if err != nil {
v2Claim := new(V2Claim)
err := v2Claim.Unmarshal(serialized)
if err != nil {
v3Claim := new(V3Claim)
err := v3Claim.Unmarshal(serialized)
if err != nil {
return nil, errors.Prefix("Claim value has no matching verion", err)
}
helper.Claim, err = migrateV3Claim(*v3Claim)
if err != nil {
return nil, errors.Prefix("V3 Metadata Migration Error", err)
}
return helper, nil
}
helper.Claim, err = migrateV2Claim(*v2Claim)
if err != nil {
return nil, errors.Prefix("V2 Metadata Migration Error ", err)
}
return helper, nil
}
helper.Claim, err = migrateV1Claim(*v1Claim)
if err != nil {
return nil, errors.Prefix("V1 Metadata Migration Error ", err)
}
return helper, nil
} }
func (c *ClaimHelper) GetStream() *pb.Stream { func (c *ClaimHelper) GetStream() *pb.Stream {

146
claim/migration.go Normal file
View file

@ -0,0 +1,146 @@
package claim
import (
"encoding/hex"
"github.com/btcsuite/btcutil/base58"
"github.com/lbryio/types/go"
)
const lbrySDHash = "lbry_sd_hash"
func newClaim() *pb.Claim {
pbClaim := new(pb.Claim)
stream := new(pb.Stream)
metadata := new(pb.Metadata)
source := new(pb.Source)
pubSig := new(pb.Signature)
fee := new(pb.Fee)
metadata.Fee = fee
stream.Metadata = metadata
stream.Source = source
pbClaim.Stream = stream
pbClaim.PublisherSignature = pubSig
//Fee version
feeVersion := pb.Fee__0_0_1
pbClaim.GetStream().GetMetadata().GetFee().Version = &feeVersion
//Metadata version
mdVersion := pb.Metadata__0_1_0
pbClaim.GetStream().GetMetadata().Version = &mdVersion
//Source version
srcVersion := pb.Source__0_0_1
pbClaim.GetStream().GetSource().Version = &srcVersion
//Stream version
streamVersion := pb.Stream__0_0_1
pbClaim.GetStream().Version = &streamVersion
//Claim version
clmVersion := pb.Claim__0_0_1
pbClaim.Version = &clmVersion
//Claim type
clmType := pb.Claim_streamType
pbClaim.ClaimType = &clmType
return pbClaim
}
func setMetaData(claim pb.Claim, author string, description string, language pb.Metadata_Language, license string,
licenseURL *string, title string, thumbnail *string, nsfw bool) {
claim.GetStream().GetMetadata().Author = &author
claim.GetStream().GetMetadata().Description = &description
claim.GetStream().GetMetadata().Language = &language
claim.GetStream().GetMetadata().License = &license
claim.GetStream().GetMetadata().Title = &title
claim.GetStream().GetMetadata().Thumbnail = thumbnail
claim.GetStream().GetMetadata().Nsfw = &nsfw
claim.GetStream().GetMetadata().LicenseUrl = licenseURL
}
func migrateV1Claim(vClaim V1Claim) (*pb.Claim, error) {
pbClaim := newClaim()
//Not part of json V1
pbClaim.PublisherSignature = nil
//Stream
// -->Universal
setFee(vClaim.Fee, pbClaim)
// -->MetaData
language := pb.Metadata_Language(pb.Metadata_Language_value[vClaim.Language])
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
vClaim.License, nil, vClaim.Title, vClaim.Thumbnail, false)
// -->Source
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
pbClaim.GetStream().GetSource().SourceType = &sourceType
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
pbClaim.GetStream().GetSource().Source = src
return pbClaim, err
}
func migrateV2Claim(vClaim V2Claim) (*pb.Claim, error) {
pbClaim := newClaim()
//Not part of json V2
pbClaim.PublisherSignature = nil
//Stream
// -->Fee
setFee(vClaim.Fee, pbClaim)
// -->MetaData
language := pb.Metadata_Language(pb.Metadata_Language_value[vClaim.Language])
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
// -->Source
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
pbClaim.GetStream().GetSource().SourceType = &sourceType
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
pbClaim.GetStream().GetSource().Source = src
return pbClaim, err
}
func migrateV3Claim(vClaim V3Claim) (*pb.Claim, error) {
pbClaim := newClaim()
//Not part of json V3
pbClaim.PublisherSignature = nil
//Stream
// -->Fee
setFee(vClaim.Fee, pbClaim)
// -->MetaData
language := pb.Metadata_Language(pb.Metadata_Language_value[vClaim.Language])
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
// -->Source
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
pbClaim.GetStream().GetSource().SourceType = &sourceType
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
pbClaim.GetStream().GetSource().Source = src
return pbClaim, err
}
func setFee(fee *Fee, pbClaim *pb.Claim) {
if fee != nil {
amount := float32(0.0)
currency := pb.Fee_LBC
address := ""
if fee.BTC != nil {
amount = fee.BTC.Amount
currency = pb.Fee_BTC
address = fee.BTC.Address
} else if fee.LBC != nil {
amount = fee.LBC.Amount
currency = pb.Fee_LBC
address = fee.LBC.Address
} else if fee.USD != nil {
amount = fee.USD.Amount
currency = pb.Fee_USD
address = fee.USD.Address
}
//Fee Settings
pbClaim.GetStream().GetMetadata().GetFee().Amount = &amount
pbClaim.GetStream().GetMetadata().GetFee().Currency = &currency
pbClaim.GetStream().GetMetadata().GetFee().Address = base58.Decode(address)
}
}

220
claim/migration_test.go Normal file
View file

@ -0,0 +1,220 @@
package claim
import (
"encoding/hex"
"testing"
"github.com/btcsuite/btcutil/base58"
)
type valueTestPair struct {
ValueAsHex string
Claim claimResult
}
type claimResult struct {
Version string
Author string
Title string
Description string
License string
LicenseURL string
FeeAmount float32
FeeCurrency string
FeeAddress string
ContentType string
Language string
LbrySDHash string
Thumbnail string
NSFW bool
}
var badJsonVersionTests = []valueTestPair{
{"7b22666565223a207b22616d6f756e74223a2035302e302c202274797065223a20224c4243222c202261646472657373223a2022625664653744716244345079485a6e6753617742686944534c626e4e76547970467a227d2c20226465736372697074696f6e223a2022466f757220636f75706c6573206d65657420666f722053756e646179206272756e6368206f6e6c7920746f20646973636f76657220746865792061726520737475636b20696e206120686f75736520746f6765746865722061732074686520776f726c64206d61792062652061626f757420746f20656e642e222c20226c6963656e7365223a20224f7363696c6c6f73636f7065204c61626f7261746f72696573222c2022617574686f72223a20225772697474656e20616e6420646972656374656420627920546f646420426572676572222c20226c616e6775616765223a2022656e222c20227469746c65223a2022497427732061204469736173746572222c2022736f7572636573223a207b226c6272795f73645f68617368223a2022646139333636323265333536323633373334343630336135353861373334636539316532653963333734303232353966346365353039626339646666396663313633633532393061663734316165613632373761623161333563376433623731227d2c20227468756d626e61696c223a2022687474703a2f2f69612e6d656469612d696d64622e636f6d2f696d616765732f4d2f4d5635424d5451774e6a597a4d5451304d6c35424d6c3542616e426e586b46745a5463774e44557a4f444d354e7740402e5f56315f5359313030305f4352302c302c3637332c313030305f414c5f2e6a7067227d",
claimResult{"0.0.1",
"Written and directed by Todd Berger",
"It's a Disaster",
"Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.",
"Oscilloscope Laboratories",
"",
50,
"LBC",
"bVde7DqbD4PyHZngSawBhiDSLbnNvTypFz",
"application/octet-stream",
"en",
"da936622e3562637344603a558a734ce91e2e9c37402259f4ce509bc9dff9fc163c5290af741aea6277ab1a35c7d3b71",
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
false,
},
},
}
var jsonVersionTests = []valueTestPair{
{"7b22666565223a207b224c4243223a207b22616d6f756e74223a20312e302c202261646472657373223a2022625077474139683775696a6f79357541767a565051773951794c6f595a6568484a6f227d7d2c20226465736372697074696f6e223a2022313030304d4220746573742066696c6520746f206d65617375726520646f776e6c6f6164207370656564206f6e204c627279207032702d6e6574776f726b2e222c20226c6963656e7365223a20224e6f6e65222c2022617574686f72223a2022726f6f74222c20226c616e6775616765223a2022456e676c697368222c20227469746c65223a2022313030304d4220737065656420746573742066696c65222c2022736f7572636573223a207b226c6272795f73645f68617368223a2022626439343033336431336634663339303837303837303163616635363562666130396366616466326633346661646634613733666238366232393564316232316137653634383035393934653435623566626336353066333062616334383734227d2c2022636f6e74656e742d74797065223a20226170706c69636174696f6e2f6f637465742d73747265616d222c20227468756d626e61696c223a20222f686f6d65726f626572742f6c6272792f73706565642e6a7067227d",
claimResult{"0.0.1",
"root",
"1000MB speed test file",
"1000MB test file to measure download speed on Lbry p2p-network.",
"None",
"",
1,
"LBC",
"bPwGA9h7uijoy5uAvzVPQw9QyLoYZehHJo",
"application/octet-stream",
"UNKNOWN_LANGUAGE", //"English" is not supported for conversion.
"bd94033d13f4f3908708701caf565bfa09cfadf2f34fadf4a73fb86b295d1b21a7e64805994e45b5fbc650f30bac4874",
"/homerobert/lbry/speed.jpg",
false,
},
},
{"7b22666565223a207b224c4243223a207b22616d6f756e74223a2035302e302c202261646472657373223a2022624c5673336966507275795a6e70596d46665432544c416d68715a76676a70514461227d7d2c20226465736372697074696f6e223a2022466f757220636f75706c6573206d65657420666f722053756e646179206272756e6368206f6e6c7920746f20646973636f76657220746865792061726520737475636b20696e206120686f75736520746f6765746865722061732074686520776f726c64206d61792062652061626f757420746f20656e642e222c20226c6963656e7365223a20224f7363696c6c6f73636f7065204c61626f7261746f72696573222c2022617574686f72223a20225772697474656e20616e6420646972656374656420627920546f646420426572676572222c20226c616e6775616765223a2022656e222c20227469746c65223a2022497427732061204469736173746572222c2022736f7572636573223a207b226c6272795f73645f68617368223a2022646363316266323838393361353033376561623965346139636437613462666536663736616436633231393730656134636565653031323266353032656630373936353764346463613435366234626533323439383439633465313836386238227d2c2022636f6e74656e742d74797065223a2022766964656f2f717569636b74696d65222c20227468756d626e61696c223a2022687474703a2f2f69612e6d656469612d696d64622e636f6d2f696d616765732f4d2f4d5635424d5451774e6a597a4d5451304d6c35424d6c3542616e426e586b46745a5463774e44557a4f444d354e7740402e5f56315f5359313030305f4352302c302c3637332c313030305f414c5f2e6a7067227d",
claimResult{"0.0.1",
"Written and directed by Todd Berger",
"It's a Disaster",
"Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.",
"Oscilloscope Laboratories",
"",
50,
"LBC",
"bLVs3ifPruyZnpYmFfT2TLAmhqZvgjpQDa",
"video/quicktime",
"en",
"dcc1bf28893a5037eab9e4a9cd7a4bfe6f76ad6c21970ea4ceee0122f502ef079657d4dca456b4be3249849c4e1868b8",
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
false,
},
},
{"7b226465736372697074696f6e223a202241647669736f7220416c6578205461626172726f6b206769766573206869732074616b65206f6e204c4252592e222c20226c6963656e7365223a20224c4252592c20496e632e222c2022617574686f72223a202253616d75656c20427279616e222c20226c616e6775616765223a2022656e222c20227469746c65223a20224d65657420746865205465616d20457069736f64652031222c2022736f7572636573223a207b226c6272795f73645f68617368223a2022373939613164653933623865353536643766363638313033613666666334386163356664363830316464346438396361653637373363383064383163323833373130666434666432356564363864306462656565323638663832393134313435227d2c2022636f6e74656e742d74797065223a2022766964656f2f6d7034227d",
claimResult{"0.0.1",
"Samuel Bryan",
"Meet the Team Episode 1",
"Advisor Alex Tabarrok gives his take on LBRY.",
"LBRY, Inc.",
"",
0,
"UNKNOWN_CURRENCY",
"",
"video/mp4",
"en",
"799a1de93b8e556d7f668103a6ffc48ac5fd6801dd4d89cae6773c80d81c283710fd4fd25ed68d0dbeee268f82914145",
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
false,
},
},
{"7b226c616e6775616765223a2022656e222c2022666565223a207b22555344223a207b22616d6f756e74223a20302e30312c202261646472657373223a2022624d486d5a4b5a6250713662504245514663384d5870694468463966374d56784d52227d7d2c2022736f7572636573223a207b226c6272795f73645f68617368223a2022326264386439646431613231386337663536373137653533666135313065666435613863303839656431663236373561306638643062356238626233633165643338336362396633616562396238393137383937363133303532393339373961227d2c20226465736372697074696f6e223a2022636c6f756473222c20226c6963656e7365223a2022637265617469766520636f6d6d6f6e73222c2022617574686f72223a202268747470733a2f2f7777772e76696465657a792e636f6d2f636c6f7564732f323637362d6461726b2d73746f726d2d636c6f7564732d726f79616c74792d667265652d68642d73746f636b2d766964656f222c20226e736677223a2066616c73652c20227469746c65223a2022636c6f756473222c2022636f6e74656e742d74797065223a2022766964656f2f6d7034222c2022766572223a2022302e302e32227d",
claimResult{"0.0.2",
"https://www.videezy.com/clouds/2676-dark-storm-clouds-royalty-free-hd-stock-video",
"clouds",
"clouds",
"creative commons",
"",
0.01,
"USD",
"bMHmZKZbPq6bPBEQFc8MXpiDhF9f7MVxMR",
"video/mp4",
"en",
"2bd8d9dd1a218c7f56717e53fa510efd5a8c089ed1f2675a0f8d0b5b8bb3c1ed383cb9f3aeb9b891789761305293979a",
"",
false,
},
},
{"7b226c6963656e7365223a2022437265617469766520436f6d6d6f6e73204174747269627574696f6e20332e3020556e6974656420537461746573222c2022666565223a207b224c4243223a207b22616d6f756e74223a20312c202261646472657373223a20226256507157775966766a424859426f7575766b6e62514d58555a46764c644573354d227d7d2c2022766572223a2022302e302e32222c20226465736372697074696f6e223a20227a222c20226c616e6775616765223a2022656e222c2022617574686f72223a202279222c20227469746c65223a202278222c2022736f7572636573223a207b226c6272795f73645f68617368223a2022376332316565323337333234653561353061333432353632306665366363343030643363636363303535313938363763646131623963313061393737313934653331323030343134643837313436626666343730626162376637643735343738227d2c20226e736677223a2066616c73652c20226c6963656e73655f75726c223a202268747470733a2f2f6372656174697665636f6d6d6f6e732e6f72672f6c6963656e7365732f62792f332e302f75732f6c6567616c636f6465222c2022636f6e74656e742d74797065223a2022746578742f706c61696e227d",
claimResult{"0.0.2",
"y",
"x",
"z",
"Creative Commons Attribution 3.0 United States",
"https://creativecommons.org/licenses/by/3.0/us/legalcode",
1,
"LBC",
"bVPqWwYfvjBHYBouuvknbQMXUZFvLdEs5M",
"text/plain",
"en",
"7c21ee237324e5a50a3425620fe6cc400d3cccc05519867cda1b9c10a977194e31200414d87146bff470bab7f7d75478",
"",
false,
},
},
{"7b22666565223a207b22555344223a207b22616d6f756e74223a20302e342c202261646472657373223a202262485365334b417674565352346d365331317a6475754639584874777363446a6f45227d7d2c2022766572223a2022302e302e33222c20226c6963656e7365223a2022437265617469766520436f6d6d6f6e73204174747269627574696f6e20332e3020556e6974656420537461746573222c20226c616e6775616765223a2022656e222c20227469746c65223a2022526561647920506c61796572204f6e652028417564696f626f6f6b2031206f66203229222c2022617574686f72223a202245726e65737420436c696e65222c2022736f7572636573223a207b226c6272795f73645f68617368223a2022333430653164646130653834313463323166616662623166323866326338623338343832316665306431653261373134336134383130353435653634653236613431303530343264346434376463393735346236313865636466653064313931227d2c20226e736677223a2066616c73652c2022636f6e74656e745f74797065223a2022617564696f2f6d706567222c20226c6963656e73655f75726c223a202268747470733a2f2f6372656174697665636f6d6d6f6e732e6f72672f6c6963656e7365732f62792f332e302f75732f6c6567616c636f6465222c20227468756d626e61696c223a2022687474703a2f2f692e696d6775722e636f6d2f6c794b45485a632e6a7067222c20226465736372697074696f6e223a2022496e20746865207965617220323034342c2074686520776f726c64206973206772697070656420627920616e20656e65726779206372697369732063617573696e67207769646573707265616420736f6369616c2070726f626c656d7320616e642065636f6e6f6d696320737461676e6174696f6e2e20546865207072696d6172792065736361706520666f72206d6f73742070656f706c6520697320746865204f415349532c2061207669727475616c20756e6976657273652c20616363657373656420776974682061207669736f7220616e642068617074696320676c6f7665732e2049742066756e6374696f6e7320626f746820617320616e204d4d4f52504720616e642061732061207669727475616c20736f63696574792c2077697468206974732063757272656e6379206265696e6720746865206d6f737420737461626c652063757272656e637920696e2074686520776f726c642e204974207761732063726561746564206279204a616d65732048616c6c696461792c2077686f73652077696c6c206c656674206120736572696573206f6620636c75657320746f776172647320616e20456173746572204567672077697468696e20746865204f41534953207468617420776f756c64206772616e742077686f6576657220666f756e6420697420626f74682068697320666f7274756e6520616e6420636f6e74726f6c206f6620746865204f4153495320697473656c662e205468697320686173206c656420746f20616e20696e74656e736520696e74657265737420696e20616c6c2061737065637473206f662038307320706f702063756c747572652c2077686963682048616c6c69646179206d61646520636c65617220776f756c6420626520657373656e7469616c20746f2066696e64696e6720686973206567672e227d",
claimResult{"0.0.3",
"Ernest Cline",
"Ready Player One (Audiobook 1 of 2)",
"In the year 2044, the world is gripped by an energy crisis causing widespread social problems and economic stagnation. The primary escape for most people is the OASIS, a virtual universe, accessed with a visor and haptic gloves. It functions both as an MMORPG and as a virtual society, with its currency being the most stable currency in the world. It was created by James Halliday, whose will left a series of clues towards an Easter Egg within the OASIS that would grant whoever found it both his fortune and control of the OASIS itself. This has led to an intense interest in all aspects of 80s pop culture, which Halliday made clear would be essential to finding his egg.",
"Creative Commons Attribution 3.0 United States",
"https://creativecommons.org/licenses/by/3.0/us/legalcode",
0.4,
"USD",
"bHSe3KAvtVSR4m6S11zduuF9XHtwscDjoE",
"audio/mpeg",
"en",
"340e1dda0e8414c21fafbb1f28f2c8b384821fe0d1e2a7143a4810545e64e26a4105042d4d47dc9754b618ecdfe0d191",
"http://i.imgur.com/lyKEHZc.jpg",
false,
},
},
{"7b22666565223a207b224c4243223a207b22616d6f756e74223a20312c202261646472657373223a202262525478744355706a3654764a48675763527347634861467972524c6b6b69586747227d7d2c2022766572223a2022302e302e33222c20226c6963656e7365223a2022436f707972696768742032303136206272617a7a657273222c20226c616e6775616765223a2022656e222c20227469746c65223a2022686f7420706f726e222c2022617574686f72223a20226272617a7a657273222c2022736f7572636573223a207b226c6272795f73645f68617368223a2022666330646163356366633532363335343936336666313736396636653733396334653432613037393034323066666162396661336236343031653933616535613035313565666639363066386339633237323930376564613666636261323534227d2c20226e736677223a20747275652c2022636f6e74656e745f74797065223a2022766964656f2f6d7034222c20226465736372697074696f6e223a2022686f7420706f726e5c6e6272617a7a657273227d",
claimResult{"0.0.3",
"brazzers",
"hot porn",
"hot porn\nbrazzers",
"Copyright 2016 brazzers",
"",
1,
"LBC",
"bRTxtCUpj6TvJHgWcRsGcHaFyrRLkkiXgG",
"video/mp4",
"en",
"fc0dac5cfc526354963ff1769f6e739c4e42a0790420ffab9fa3b6401e93ae5a0515eff960f8c9c272907eda6fcba254",
"",
true,
},
},
}
func TestMigrationFromJSON(t *testing.T) {
for _, pair := range jsonVersionTests {
valueBytes, err := hex.DecodeString(pair.ValueAsHex)
if err != nil {
t.Error(err)
}
helper, err := DecodeClaimBytes(valueBytes, "lbrycrd_main")
if err != nil {
t.Error("Decode error: ", err)
}
if helper.Claim.GetStream().GetMetadata().GetAuthor() != pair.Claim.Author {
t.Error("Author mismatch: expected", pair.Claim.Author, "got", helper.Claim.GetStream().GetMetadata().GetAuthor())
}
if helper.Claim.GetStream().GetMetadata().GetTitle() != pair.Claim.Title {
t.Error("Title mismatch: expected", pair.Claim.Title, "got", helper.Claim.GetStream().GetMetadata().GetTitle())
}
if helper.Claim.GetStream().GetMetadata().GetDescription() != pair.Claim.Description {
t.Error("Description mismatch: expected", pair.Claim.Description, "got", helper.Claim.GetStream().GetMetadata().GetDescription())
}
if helper.Claim.GetStream().GetMetadata().GetLicense() != pair.Claim.License {
t.Error("License mismatch: expected", pair.Claim.License, "got", helper.Claim.GetStream().GetMetadata().GetLicense())
}
if helper.Claim.GetStream().GetMetadata().GetLicenseUrl() != pair.Claim.LicenseURL {
t.Error("LicenseURL mismatch: expected", pair.Claim.LicenseURL, "got", helper.Claim.GetStream().GetMetadata().GetLicenseUrl())
}
if helper.Claim.GetStream().GetMetadata().GetFee().GetAmount() != pair.Claim.FeeAmount {
t.Error("Fee Amount mismatch: expected", pair.Claim.FeeAmount, "got", helper.Claim.GetStream().GetMetadata().GetFee().GetAmount())
}
if helper.Claim.GetStream().GetMetadata().GetFee().GetCurrency().String() != pair.Claim.FeeCurrency {
t.Error("Fee Currency mismatch: expected", pair.Claim.FeeCurrency, "got", helper.Claim.GetStream().GetMetadata().GetFee().GetCurrency())
}
hexaddress := base58.Encode(helper.Claim.GetStream().GetMetadata().GetFee().GetAddress())
if hexaddress != pair.Claim.FeeAddress {
t.Error("Fee Address mismatch: expected", pair.Claim.FeeAddress, "got", hexaddress)
}
if helper.Claim.GetStream().GetSource().GetContentType() != pair.Claim.ContentType {
t.Error("ContentType mismatch: expected", pair.Claim.ContentType, "got", helper.Claim.GetStream().GetSource().GetContentType())
}
if helper.Claim.GetStream().GetMetadata().GetLanguage().String() != pair.Claim.Language {
t.Error("Language mismatch: expected ", pair.Claim.Language, " got ", helper.Claim.GetStream().GetMetadata().GetLanguage().String())
}
content := hex.EncodeToString(helper.Claim.GetStream().GetSource().GetSource())
if content != pair.Claim.LbrySDHash {
t.Error("Source mismatch: expected", pair.Claim.LbrySDHash, "got", content)
}
}
}

125
claim/schema.go Normal file
View file

@ -0,0 +1,125 @@
package claim
import (
"encoding/json"
"github.com/lbryio/lbry.go/errors"
)
// V1Claim is the first version of claim metadata used by lbry.
type V1Claim struct {
Version string `json:"ver,omitempty"`
Title string `json:"title"` //Required
Description string `json:"description"` //Required
Author string `json:"author"` //Required
Language string `json:"language"` //Required
License string `json:"license"` //Required
Sources Sources `json:"sources"` //Required
ContentType string `json:"content-type"` //Required
Thumbnail *string `json:"thumbnail,omitempty"`
Fee *Fee `json:"fee,omitempty"`
Contact *int `json:"contact,omitempty"`
PubKey *string `json:"pubkey,omitempty"`
}
// V2Claim is the second version of claim metadata used by lbry.
type V2Claim struct {
Version string `json:"ver"` //Required
Title string `json:"title"` //Required
Description string `json:"description"` //Required
Author string `json:"author"` //Required
Language string `json:"language"` //Required
License string `json:"license"` //Required
Sources Sources `json:"sources"` //Required
ContentType string `json:"content-type"` //Required
Thumbnail *string `json:"thumbnail,omitempty"`
Fee *Fee `json:"fee,omitempty"`
Contact *int `json:"contact,omitempty"`
PubKey *string `json:"pubkey,omitempty"`
LicenseURL *string `json:"license_url,omitempty"`
NSFW bool `json:"nsfw"` //Required
}
// V3Claim is the third version of claim metadata used by lbry.
type V3Claim struct {
Version string `json:"ver"` //Required
Title string `json:"title"` //Required
Description string `json:"description"` //Required
Author string `json:"author"` //Required
Language string `json:"language"` //Required
License string `json:"license"` //Required
Sources Sources `json:"sources"` //Required
ContentType string `json:"content_type"` //Required
Thumbnail *string `json:"thumbnail,omitempty"`
Fee *Fee `json:"fee,omitempty"`
Contact *int `json:"contact,omitempty"`
PubKey *string `json:"pubkey,omitempty"`
LicenseURL *string `json:"license_url,omitempty"`
NSFW bool `json:"nsfw"` //Required
Sig *string `json:"sig"`
}
// FeeInfo is the structure of fee information used by lbry.
type FeeInfo struct {
Amount float32 `json:"amount"` //Required
Address string `json:"address"` //Required
}
// Sources is the structure of Sources that can be used for a claim. Sources mainly include lbrysdhash but could be from
// elsewhere in the future.
type Sources struct {
LbrySDHash string `json:"lbry_sd_hash"` //Required
BTIH string `json:"btih"` //Required
URL string `json:"url"` //Required
}
// Fee is the structure used for different currencies allowed for claims.
type Fee struct {
LBC *FeeInfo `json:"LBC,omitempty"`
BTC *FeeInfo `json:"BTC,omitempty"`
USD *FeeInfo `json:"USD,omitempty"`
}
// Unmarshal is an implementation to unmarshal the V1 claim from json. Main addition is to check the version.
func (c *V1Claim) Unmarshal(value []byte) error {
err := json.Unmarshal(value, c)
if err != nil {
return err
} //Version can be blank for version 1
if c.Version != "" && c.Version != "0.0.1" {
err = errors.Base("Incorrect version, expected 0.0.1 found " + c.Version)
return err
}
//ToDo - restrict to required fields?
return nil
}
// Unmarshal is an implementation to unmarshal the V2 claim from json. Main addition is to check the version.
func (c *V2Claim) Unmarshal(value []byte) error {
err := json.Unmarshal(value, c)
if err != nil {
return err
}
if c.Version != "0.0.2" {
err = errors.Base("Incorrect version, expected 0.0.2 found " + c.Version)
return err
}
return nil
}
// Unmarshal is an implementation to unmarshal the V3 claim from json. Main addition is to check the version.
func (c *V3Claim) Unmarshal(value []byte) error {
err := json.Unmarshal(value, c)
if err != nil {
return err
}
if c.Version != "0.0.3" {
err = errors.Base("Incorrect version, expected 0.0.3 found " + c.Version)
return err
}
return nil
}