Compare commits
10 commits
remove_mig
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
761687c40d | ||
|
b14fb6c18b | ||
|
6d2f69a36f | ||
|
d701bab7f6 | ||
|
c54836bca0 | ||
|
322c658307 | ||
|
bad2d869f5 | ||
|
414540ec6d | ||
|
9159c7602d | ||
|
50996a6b0d |
37 changed files with 1217 additions and 716 deletions
|
@ -1,78 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
"encoding/hex"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
"github.com/lbryio/lbryschema.go/claim"
|
||||
)
|
||||
|
||||
//export VerifySignature
|
||||
func VerifySignature(claimHex string, certificateHex string, claimAddress string, certificateId string, blockchainName string) bool {
|
||||
decodedClaim, err := claim.DecodeClaimHex(claimHex, blockchainName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
decodedCertificate, err := claim.DecodeClaimHex(certificateHex, blockchainName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
result, err := decodedClaim.ValidateClaimSignature(decodedCertificate, claimAddress, certificateId, blockchainName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
//export DecodeClaimHex
|
||||
func DecodeClaimHex(claimHex string, blockchainName string) *C.char {
|
||||
decodedClaim, err := claim.DecodeClaimHex(claimHex, blockchainName)
|
||||
if err != nil {
|
||||
return C.CString("decode error: " + err.Error())
|
||||
}
|
||||
decoded, err := decodedClaim.RenderJSON()
|
||||
if err != nil {
|
||||
return C.CString("encode error: " + err.Error())
|
||||
}
|
||||
return C.CString(decoded)
|
||||
}
|
||||
|
||||
//export SerializeClaimFromJSON
|
||||
func SerializeClaimFromJSON(claimJSON string, blockchainName string) *C.char {
|
||||
decodedClaim, err := claim.DecodeClaimJSON(claimJSON, blockchainName)
|
||||
if err != nil {
|
||||
return C.CString("decode error: " + err.Error())
|
||||
}
|
||||
SerializedHex, err := decodedClaim.SerializedHexString()
|
||||
if err != nil {
|
||||
return C.CString("encode error: " + err.Error())
|
||||
}
|
||||
return C.CString(SerializedHex)
|
||||
}
|
||||
|
||||
//export DecodeAddress
|
||||
func DecodeAddress(addressString string, blockchainName string) *C.char {
|
||||
addressBytes, err := address.DecodeAddress(addressString, blockchainName)
|
||||
if err != nil {
|
||||
return C.CString("error: " + err.Error())
|
||||
}
|
||||
return C.CString(hex.EncodeToString(addressBytes[:]))
|
||||
}
|
||||
|
||||
//export EncodeAddress
|
||||
func EncodeAddress(addressChars string, blockchainName string) *C.char {
|
||||
addressBytes := [25]byte{}
|
||||
if len(addressChars) != 25 {
|
||||
return C.CString("error: address is not 25 bytes")
|
||||
}
|
||||
for i := range addressBytes {
|
||||
addressBytes[i] = byte(addressChars[i])
|
||||
}
|
||||
encodedAddress, err := address.EncodeAddress(addressBytes, blockchainName)
|
||||
if err != nil {
|
||||
return C.CString("error: " + err.Error())
|
||||
}
|
||||
return C.CString(encodedAddress)
|
||||
}
|
||||
|
||||
func main() {}
|
6
build.sh
6
build.sh
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
go build ./...
|
||||
go build ./cli/lbryschema-cli.go
|
||||
go build -o lbryschema-python-binding.so -buildmode=c-shared ./binding/lbryschema-python-binding.go
|
174
claim/claim.go
174
claim/claim.go
|
@ -1,174 +0,0 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
"github.com/lbryio/lbry.go/errors"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
"github.com/lbryio/types/go"
|
||||
)
|
||||
|
||||
type ClaimHelper struct {
|
||||
*pb.Claim
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateAddresses(blockchainName string) error {
|
||||
// check the validity of a fee address
|
||||
if c.GetClaimType() == pb.Claim_streamType {
|
||||
fee := c.GetStream().GetMetadata().GetFee()
|
||||
if fee != nil {
|
||||
tmp_addr := fee.GetAddress()
|
||||
if len(tmp_addr) != 25 {
|
||||
return errors.Err("invalid address length: " + string(len(tmp_addr)) + "!")
|
||||
}
|
||||
addr := [25]byte{}
|
||||
for i := range addr {
|
||||
addr[i] = tmp_addr[i]
|
||||
}
|
||||
_, err := address.EncodeAddress(addr, blockchainName)
|
||||
if err != nil {
|
||||
return errors.Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateCertificate() error {
|
||||
certificate := c.GetCertificate()
|
||||
if certificate == nil {
|
||||
return nil
|
||||
}
|
||||
keyType := certificate.GetKeyType()
|
||||
_, err := c.GetCertificatePublicKey()
|
||||
if err != nil {
|
||||
return errors.Err(err)
|
||||
}
|
||||
if keyType.String() != SECP256k1 {
|
||||
return errors.Err("wrong curve: " + keyType.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) LoadFromBytes(raw_claim []byte, blockchainName string) error {
|
||||
if c.String() != "" {
|
||||
return errors.Err("already initialized")
|
||||
}
|
||||
if len(raw_claim) < 1 {
|
||||
return errors.Err("there is nothing to decode")
|
||||
}
|
||||
|
||||
claim_pb := &pb.Claim{}
|
||||
err := proto.Unmarshal(raw_claim, claim_pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*c = ClaimHelper{claim_pb}
|
||||
err = c.ValidateAddresses(blockchainName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ValidateCertificate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) LoadFromHexString(claim_hex string, blockchainName string) error {
|
||||
buf, err := hex.DecodeString(claim_hex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.LoadFromBytes(buf, blockchainName)
|
||||
}
|
||||
|
||||
func DecodeClaimProtoBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
|
||||
claim := &ClaimHelper{&pb.Claim{}}
|
||||
err := claim.LoadFromBytes(serialized, blockchainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return claim, nil
|
||||
}
|
||||
|
||||
func DecodeClaimHex(serialized string, blockchainName string) (*ClaimHelper, error) {
|
||||
claim_bytes, err := hex.DecodeString(serialized)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DecodeClaimBytes(claim_bytes, blockchainName)
|
||||
}
|
||||
|
||||
func DecodeClaimJSON(claimJSON string, blockchainName string) (*ClaimHelper, error) {
|
||||
c := &pb.Claim{}
|
||||
err := jsonpb.UnmarshalString(claimJSON, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ClaimHelper{c}, 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 {
|
||||
if c != nil {
|
||||
return c.Stream
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetCertificate() *pb.Certificate {
|
||||
if c != nil {
|
||||
return c.Certificate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetPublisherSignature() *pb.Signature {
|
||||
if c != nil {
|
||||
return c.PublisherSignature
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
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 = ¤cy
|
||||
pbClaim.GetStream().GetMetadata().GetFee().Address = base58.Decode(address)
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/lbryio/types/go"
|
||||
)
|
||||
|
||||
func (c *ClaimHelper) Serialized() ([]byte, error) {
|
||||
serialized := c.String()
|
||||
if serialized == "" {
|
||||
return nil, errors.New("not initialized")
|
||||
}
|
||||
v := c.GetVersion()
|
||||
t := c.GetClaimType()
|
||||
|
||||
return proto.Marshal(
|
||||
&pb.Claim{
|
||||
Version: &v,
|
||||
ClaimType: &t,
|
||||
Stream: c.GetStream(),
|
||||
Certificate: c.GetCertificate(),
|
||||
PublisherSignature: c.GetPublisherSignature()})
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetProtobuf() *pb.Claim {
|
||||
v := c.GetVersion()
|
||||
t := c.GetClaimType()
|
||||
|
||||
return &pb.Claim{
|
||||
Version: &v,
|
||||
ClaimType: &t,
|
||||
Stream: c.GetStream(),
|
||||
Certificate: c.GetCertificate(),
|
||||
PublisherSignature: c.GetPublisherSignature()}
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) SerializedHexString() (string, error) {
|
||||
serialized, err := c.Serialized()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
serialized_hex := hex.EncodeToString(serialized)
|
||||
return serialized_hex, nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) SerializedNoSignature() ([]byte, error) {
|
||||
if c.String() == "" {
|
||||
return nil, errors.New("not initialized")
|
||||
}
|
||||
if c.GetPublisherSignature() == nil {
|
||||
serialized, err := c.Serialized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return serialized, nil
|
||||
} else {
|
||||
clone := &pb.Claim{}
|
||||
proto.Merge(clone, c.GetProtobuf())
|
||||
proto.ClearAllExtensions(clone.PublisherSignature)
|
||||
clone.PublisherSignature = nil
|
||||
return proto.Marshal(clone)
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type publicKeyInfo struct {
|
||||
Raw asn1.RawContent
|
||||
Algorithm pkix.AlgorithmIdentifier
|
||||
PublicKey asn1.BitString
|
||||
}
|
||||
|
||||
const SECP256k1 = "SECP256k1"
|
||||
|
||||
//const NIST256p = "NIST256p"
|
||||
//const NIST384p = "NIST384p"
|
||||
|
||||
func GetClaimSignatureDigest(claimAddress [25]byte, certificateId [20]byte, serializedNoSig []byte) [32]byte {
|
||||
var combined []byte
|
||||
for _, c := range claimAddress {
|
||||
combined = append(combined, c)
|
||||
}
|
||||
for _, c := range serializedNoSig {
|
||||
combined = append(combined, c)
|
||||
}
|
||||
for _, c := range certificateId {
|
||||
combined = append(combined, c)
|
||||
}
|
||||
digest := sha256.Sum256(combined)
|
||||
return [32]byte(digest)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetCertificatePublicKey() (*btcec.PublicKey, error) {
|
||||
derBytes := c.GetCertificate().GetPublicKey()
|
||||
pub := publicKeyInfo{}
|
||||
asn1.Unmarshal(derBytes, &pub)
|
||||
pubkeyBytes := []byte(pub.PublicKey.Bytes)
|
||||
p, err := btcec.ParsePubKey(pubkeyBytes, btcec.S256())
|
||||
if err != nil {
|
||||
return &btcec.PublicKey{}, err
|
||||
}
|
||||
return p, err
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) VerifyDigest(certificate *ClaimHelper, signature [64]byte, digest [32]byte) bool {
|
||||
publicKey, err := certificate.GetCertificatePublicKey()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if c.PublisherSignature.SignatureType.String() == SECP256k1 {
|
||||
R := &big.Int{}
|
||||
S := &big.Int{}
|
||||
R.SetBytes(signature[0:32])
|
||||
S.SetBytes(signature[32:64])
|
||||
return ecdsa.Verify(publicKey.ToECDSA(), digest[:], R, S)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateClaimSignatureBytes(certificate *ClaimHelper, claimAddress [25]byte, certificateId [20]byte, blockchainName string) (bool, error) {
|
||||
signature := c.GetPublisherSignature()
|
||||
if signature == nil {
|
||||
return false, errors.New("claim does not have a signature")
|
||||
}
|
||||
signatureSlice := signature.GetSignature()
|
||||
signatureBytes := [64]byte{}
|
||||
for i := range signatureBytes {
|
||||
signatureBytes[i] = signatureSlice[i]
|
||||
}
|
||||
|
||||
claimAddress, err := address.ValidateAddress(claimAddress, blockchainName)
|
||||
if err != nil {
|
||||
return false, errors.New("invalid address")
|
||||
}
|
||||
|
||||
serializedNoSig, err := c.SerializedNoSignature()
|
||||
if err != nil {
|
||||
return false, errors.New("serialization error")
|
||||
}
|
||||
|
||||
claimDigest := GetClaimSignatureDigest(claimAddress, certificateId, serializedNoSig)
|
||||
return c.VerifyDigest(certificate, signatureBytes, claimDigest), nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateClaimSignature(certificate *ClaimHelper, claimAddress string, certificateId string, blockchainName string) (bool, error) {
|
||||
addressBytes, err := address.DecodeAddress(claimAddress, blockchainName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
certificateIdSlice, err := hex.DecodeString(certificateId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
certificateIdBytes := [20]byte{}
|
||||
for i := range certificateIdBytes {
|
||||
certificateIdBytes[i] = certificateIdSlice[i]
|
||||
}
|
||||
return c.ValidateClaimSignatureBytes(certificate, addressBytes, certificateIdBytes, blockchainName)
|
||||
}
|
1
readme.md
Normal file
1
readme.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Repo moved to https://github.com/lbryio/lbry.go/tree/master/schema
|
0
.gitignore → schema/.gitignore
vendored
0
.gitignore → schema/.gitignore
vendored
|
@ -1,14 +1,14 @@
|
|||
package address
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address/base58"
|
||||
)
|
||||
|
||||
func DecodeAddress(address string, blockchainName string) ([addressLength]byte, error) {
|
||||
decoded, err := base58.DecodeBase58(address, addressLength)
|
||||
if err != nil {
|
||||
return [addressLength]byte{}, errors.New("failed to decode")
|
||||
return [addressLength]byte{}, errors.Err("failed to decode")
|
||||
}
|
||||
buf := [addressLength]byte{}
|
||||
for i, b := range decoded {
|
|
@ -1,15 +1,16 @@
|
|||
package address
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address/base58"
|
||||
)
|
||||
|
||||
const lbrycrdMainPubkeyPrefix = byte(85)
|
||||
const lbrycrdMainScriptPrefix = byte(122)
|
||||
|
||||
const lbrycrdTestnetPubkeyPrefix = byte(111)
|
||||
const lbrycrdTestnetScriptPrefix = byte(196)
|
||||
|
||||
const lbrycrdRegtestPubkeyPrefix = byte(111)
|
||||
const lbrycrdRegtestScriptPrefix = byte(196)
|
||||
|
||||
|
@ -17,6 +18,7 @@ const prefixLength = 1
|
|||
const pubkeyLength = 20
|
||||
const checksumLength = 4
|
||||
const addressLength = prefixLength + pubkeyLength + checksumLength
|
||||
|
||||
const lbrycrdMain = "lbrycrd_main"
|
||||
const lbrycrdTestnet = "lbrycrd_testnet"
|
||||
const lbrycrdRegtest = "lbrycrd_regtest"
|
||||
|
@ -52,16 +54,16 @@ func ChecksumIsValid(address [addressLength]byte) bool {
|
|||
|
||||
func ValidateAddress(address [addressLength]byte, blockchainName string) ([addressLength]byte, error) {
|
||||
if blockchainName != lbrycrdMain && blockchainName != lbrycrdTestnet && blockchainName != lbrycrdRegtest {
|
||||
return address, errors.New("invalid blockchain name")
|
||||
return address, errors.Err("invalid blockchain name")
|
||||
}
|
||||
if !PrefixIsValid(address, blockchainName) {
|
||||
return address, errors.New("invalid prefix")
|
||||
return address, errors.Err("invalid prefix")
|
||||
}
|
||||
if !PubKeyIsValid(address) {
|
||||
return address, errors.New("invalid pubkey")
|
||||
return address, errors.Err("invalid pubkey")
|
||||
}
|
||||
if !ChecksumIsValid(address) {
|
||||
return address, errors.New("invalid address checksum")
|
||||
return address, errors.Err("invalid address checksum")
|
||||
}
|
||||
return address, nil
|
||||
}
|
5
schema/build.sh
Executable file
5
schema/build.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
go build ./...
|
||||
go build ./cli/lbryschema-cli.go
|
249
schema/claim/claim.go
Normal file
249
schema/claim/claim.go
Normal file
|
@ -0,0 +1,249 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
legacy_pb "github.com/lbryio/types/v1/go"
|
||||
pb "github.com/lbryio/types/v2/go"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type version byte
|
||||
|
||||
func (v version) byte() byte {
|
||||
return byte(v)
|
||||
}
|
||||
|
||||
const (
|
||||
NoSig = version(byte(0))
|
||||
//Signature using ECDSA SECP256k1 key and SHA-256 hash.
|
||||
WithSig = version(byte(1))
|
||||
UNKNOWN = version(byte(2))
|
||||
)
|
||||
|
||||
type ClaimHelper struct {
|
||||
*pb.Claim
|
||||
LegacyClaim *legacy_pb.Claim
|
||||
ClaimID []byte
|
||||
Version version
|
||||
Signature []byte
|
||||
Payload []byte
|
||||
}
|
||||
|
||||
const migrationErrorMessage = "migration from v1 to v2 protobuf failed with: "
|
||||
|
||||
func (c *ClaimHelper) ValidateAddresses(blockchainName string) error {
|
||||
if c.Claim != nil { // V2
|
||||
// check the validity of a fee address
|
||||
if c.Claim.GetStream() != nil {
|
||||
fee := c.GetStream().GetFee()
|
||||
if fee != nil {
|
||||
return validateAddress(fee.GetAddress(), blockchainName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else if c.GetChannel() != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return errors.Err("claim helper created with migrated v2 protobuf claim 'invalid state'")
|
||||
}
|
||||
|
||||
func validateAddress(tmp_addr []byte, blockchainName string) error {
|
||||
if len(tmp_addr) != 25 {
|
||||
return errors.Err("invalid address length: " + strconv.FormatInt(int64(len(tmp_addr)), 10) + "!")
|
||||
}
|
||||
addr := [25]byte{}
|
||||
for i := range addr {
|
||||
addr[i] = tmp_addr[i]
|
||||
}
|
||||
_, err := address.EncodeAddress(addr, blockchainName)
|
||||
if err != nil {
|
||||
return errors.Err(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getVersionFromByte(versionByte byte) version {
|
||||
if versionByte == byte(0) {
|
||||
return NoSig
|
||||
} else if versionByte == byte(1) {
|
||||
return WithSig
|
||||
}
|
||||
|
||||
return UNKNOWN
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateCertificate() error {
|
||||
if c.GetChannel() == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := c.GetPublicKey()
|
||||
if err != nil {
|
||||
return errors.Err(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) LoadFromBytes(raw_claim []byte, blockchainName string) error {
|
||||
if c.String() != "" {
|
||||
return errors.Err("already initialized")
|
||||
}
|
||||
if len(raw_claim) < 1 {
|
||||
return errors.Err("there is nothing to decode")
|
||||
}
|
||||
|
||||
var claim_pb *pb.Claim
|
||||
var legacy_claim_pb *legacy_pb.Claim
|
||||
|
||||
version := getVersionFromByte(raw_claim[0]) //First byte = version
|
||||
pbPayload := raw_claim[1:]
|
||||
var claimID []byte
|
||||
var signature []byte
|
||||
if version == WithSig {
|
||||
if len(raw_claim) < 86 {
|
||||
return errors.Err("signature version indicated by 1st byte but not enough bytes for valid format")
|
||||
}
|
||||
claimID = raw_claim[1:21] // channel claimid = next 20 bytes
|
||||
signature = raw_claim[21:85] // signature = next 64 bytes
|
||||
pbPayload = raw_claim[85:] // protobuf payload = remaining bytes
|
||||
}
|
||||
|
||||
claim_pb = &pb.Claim{}
|
||||
err := proto.Unmarshal(pbPayload, claim_pb)
|
||||
if err != nil {
|
||||
legacy_claim_pb = &legacy_pb.Claim{}
|
||||
legacyErr := proto.Unmarshal(raw_claim, legacy_claim_pb)
|
||||
if legacyErr == nil {
|
||||
claim_pb, err = migrateV1PBClaim(*legacy_claim_pb)
|
||||
if err != nil {
|
||||
return errors.Prefix(migrationErrorMessage, err)
|
||||
}
|
||||
if legacy_claim_pb.GetPublisherSignature() != nil {
|
||||
version = WithSig
|
||||
claimID = legacy_claim_pb.GetPublisherSignature().GetCertificateId()
|
||||
signature = legacy_claim_pb.GetPublisherSignature().GetSignature()
|
||||
}
|
||||
if legacy_claim_pb.GetCertificate() != nil {
|
||||
version = NoSig
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
*c = ClaimHelper{
|
||||
Claim: claim_pb,
|
||||
LegacyClaim: legacy_claim_pb,
|
||||
ClaimID: claimID,
|
||||
Version: version,
|
||||
Signature: signature,
|
||||
Payload: pbPayload,
|
||||
}
|
||||
|
||||
// Commenting out because of a bug in SDK release allowing empty addresses.
|
||||
//err = c.ValidateAddresses(blockchainName)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
err = c.ValidateCertificate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) LoadFromHexString(claim_hex string, blockchainName string) error {
|
||||
buf, err := hex.DecodeString(claim_hex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.LoadFromBytes(buf, blockchainName)
|
||||
}
|
||||
|
||||
func DecodeClaimProtoBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
|
||||
claim := &ClaimHelper{&pb.Claim{}, nil, nil, NoSig, nil, nil}
|
||||
err := claim.LoadFromBytes(serialized, blockchainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return claim, nil
|
||||
}
|
||||
|
||||
func DecodeClaimHex(serialized string, blockchainName string) (*ClaimHelper, error) {
|
||||
claim_bytes, err := hex.DecodeString(serialized)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
return DecodeClaimBytes(claim_bytes, blockchainName)
|
||||
}
|
||||
|
||||
// DecodeClaimBytes take a byte array and tries to decode it to a protobuf claim or migrate it from either json v1,2,3 or pb v1
|
||||
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 version", 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 {
|
||||
if c != nil {
|
||||
return c.Claim.GetStream()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) CompileValue() ([]byte, error) {
|
||||
payload, err := c.serialized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var value []byte
|
||||
value = append(value, c.Version.byte())
|
||||
if c.Version == WithSig {
|
||||
value = append(value, c.ClaimID...)
|
||||
value = append(value, c.Signature...)
|
||||
}
|
||||
value = append(value, payload...)
|
||||
|
||||
return value, nil
|
||||
}
|
|
@ -13,15 +13,15 @@ func TestClaimHelper(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = helper.Serialized()
|
||||
_, err = helper.serialized()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = helper.SerializedHexString()
|
||||
_, err = helper.serializedHexString()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = helper.SerializedNoSignature()
|
||||
_, err = helper.serializedNoSignature()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
|
@ -3,8 +3,17 @@ package claim
|
|||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
pb "github.com/lbryio/types/v2/go"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
type rawClaim struct {
|
||||
Hex string
|
||||
ClaimID string
|
||||
}
|
||||
|
||||
var raw_claims = []string{
|
||||
"08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367",
|
||||
"080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65",
|
||||
|
@ -17,13 +26,21 @@ var raw_claims = []string{
|
|||
"080110011aed03080112a503080410011a3b4b41205345524159552020323136204449204a504c203432362d41205354415349554e2042414e4a4152207c4a75727573616e205053452d505754228002496e696c6168204b4120536572617975203231362079616e67206d656d62617761206d617374657220626c7573756b616e206a616c7572206e6f6e20616b746966204f6d204d6179626920507261626f776f202068747470733a2f2f7777772e796f75747562652e636f6d2f6368616e6e656c2f55435076355953496f59716f38364a525f4871626b437251202e0a5361617420696e6920616b616e206d656e656c7573757269206a616c7572206e6f6e20616b7469662042616e6a61722d50616e67616e646172616e2d43696a756c616e672e0a68747470733a2f2f7777772e796f75747562652e636f6d2f77617463683f763d4a6b4347615473774c35632a1042616d62616e6720536574796177616e321c436f7079726967687465642028636f6e7461637420617574686f722938004a2968747470733a2f2f6265726b2e6e696e6a612f7468756d626e61696c732f4a6b4347615473774c356352005a001a41080110011a302ed97c79df5eccb145f8f8e1e866be1a392004a6794347c08c7e851c5f00b1504092a9f3c0674c78805a73a33c8b1bf32209766964656f2f6d70342a5c080110031a40cbcec20908e60b5f6198aecc192d2a9e4b069aa58d9238cb7154e37c4d04f268feefe92c2705c14009acf32e7e876df180cff3afdea6c989e75b4861150d1644221402b1839207e2a706f0ba73dec0ce6b719043293d",
|
||||
}
|
||||
|
||||
func TestDecodeClaim(t *testing.T) {
|
||||
claimHex := "000aa4010a8a010a30f1303989f58396694b0c5982c97f7e9d9435841d92aa13f4b80f671c27110c469babc4fbf4bd764155eaac089cfc49e8121454554d205045204d45524e45204c41472e6d703418cad0c8012209766964656f2f6d70343230c2c9389731e2a9568f66c78d703736a8c341015ada2e46f5dcc87aa6f08ab17c02df2121d9f6ef74055827a29dfc75801a044e6f6e6532040803180a5a0908b001109001188102421054554d205045204d45524e45204c41474a0944657369206c6f636b62020801"
|
||||
claim, err := DecodeClaimHex(claimHex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err, claim.ClaimID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeClaims(t *testing.T) {
|
||||
for _, claim_hex := range raw_claims {
|
||||
claim, err := DecodeClaimHex(claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
serializedHex, err := claim.SerializedHexString()
|
||||
serializedHex, err := claim.serializedHexString()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -40,7 +57,7 @@ func TestStripSignature(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
noSig, err := claim.SerializedNoSignature()
|
||||
noSig, err := claim.serializedNoSignature()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -48,3 +65,39 @@ func TestStripSignature(t *testing.T) {
|
|||
t.Error("failed to remove signature")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateChannelClaim(t *testing.T) {
|
||||
private, err := btcec.NewPrivateKey(btcec.S256())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
pubKeyBytes, err := PublicKeyToDER(private.PubKey())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
claim := &ClaimHelper{Claim: newChannelClaim(), Version: NoSig}
|
||||
claim.GetChannel().PublicKey = pubKeyBytes
|
||||
claim.Title = "Test Channel Title"
|
||||
claim.Description = "Test Channel Description"
|
||||
claim.GetChannel().Cover = &pb.Source{Url: "http://testcoverurl.com"}
|
||||
claim.Tags = []string{"TagA", "TagB", "TagC"}
|
||||
claim.Languages = []*pb.Language{{Language: pb.Language_en}, {Language: pb.Language_es}}
|
||||
claim.Thumbnail = &pb.Source{Url: "http://thumbnailurl.com"}
|
||||
claim.GetChannel().WebsiteUrl = "http://homepageurl.com"
|
||||
claim.Locations = []*pb.Location{{Country: pb.Location_AD}, {Country: pb.Location_US, State: "NJ", City: "some city"}}
|
||||
|
||||
rawClaim, err := claim.CompileValue()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
claim, err = DecodeClaimBytes(rawClaim, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if bytes, err := claim.CompileValue(); err != nil || len(bytes) != len(rawClaim) {
|
||||
t.Error("decoded claim does not match original")
|
||||
}
|
||||
|
||||
}
|
50
schema/claim/keys.go
Normal file
50
schema/claim/keys.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
func PublicKeyToDER(publicKey *btcec.PublicKey) ([]byte, error) {
|
||||
var publicKeyBytes []byte
|
||||
var publicKeyAlgorithm pkix.AlgorithmIdentifier
|
||||
var err error
|
||||
pub := publicKey.ToECDSA()
|
||||
publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
|
||||
//ans1 encoding oid for ecdsa public key https://github.com/golang/go/blob/release-branch.go1.12/src/crypto/x509/x509.go#L457
|
||||
publicKeyAlgorithm.Algorithm = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
//asn1 encoding oid for secp256k1 https://github.com/bitpay/bitpay-go/blob/v2.2.2/key_utils/key_utils.go#L30
|
||||
paramBytes, err := asn1.Marshal(asn1.ObjectIdentifier{1, 3, 132, 0, 10})
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
publicKeyAlgorithm.Parameters.FullBytes = paramBytes
|
||||
|
||||
return asn1.Marshal(publicKeyInfo{
|
||||
Algorithm: publicKeyAlgorithm,
|
||||
PublicKey: asn1.BitString{
|
||||
Bytes: publicKeyBytes,
|
||||
BitLength: 8 * len(publicKeyBytes),
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetPublicKey() (*btcec.PublicKey, error) {
|
||||
if c.GetChannel() == nil {
|
||||
return nil, errors.Err("claim is not of type channel, so there is no public key to get")
|
||||
}
|
||||
return getPublicKeyFromBytes(c.GetChannel().PublicKey)
|
||||
}
|
||||
|
||||
func getPublicKeyFromBytes(pubKeyBytes []byte) (*btcec.PublicKey, error) {
|
||||
PKInfo := publicKeyInfo{}
|
||||
asn1.Unmarshal(pubKeyBytes, &PKInfo)
|
||||
pubkeyBytes1 := []byte(PKInfo.PublicKey.Bytes)
|
||||
return btcec.ParsePubKey(pubkeyBytes1, btcec.S256())
|
||||
}
|
36
schema/claim/keys_test.go
Normal file
36
schema/claim/keys_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
// The purpose of this test, is to make sure the function converts btcec.PublicKey to DER format the same way
|
||||
// lbry SDK does as this is the bytes that are put into protobuf and the same bytes are used for verify signatures.
|
||||
// Making sure these
|
||||
func TestPublicKeyToDER(t *testing.T) {
|
||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
cert_claim, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
p1, err := getPublicKeyFromBytes(cert_claim.Claim.GetChannel().PublicKey)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
pubkeyBytes2, err := PublicKeyToDER(p1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for i, b := range cert_claim.Claim.GetChannel().PublicKey {
|
||||
assert.Assert(t, b == pubkeyBytes2[i], "DER format in bytes must match!")
|
||||
}
|
||||
|
||||
p2, err := getPublicKeyFromBytes(pubkeyBytes2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, p1.IsEqual(p2), "The keys produced must be the same key!")
|
||||
}
|
197
schema/claim/migration.go
Normal file
197
schema/claim/migration.go
Normal file
|
@ -0,0 +1,197 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
v1pb "github.com/lbryio/types/v1/go"
|
||||
pb "github.com/lbryio/types/v2/go"
|
||||
|
||||
"github.com/btcsuite/btcutil/base58"
|
||||
)
|
||||
|
||||
const lbrySDHash = "lbry_sd_hash"
|
||||
|
||||
func newStreamClaim() *pb.Claim {
|
||||
claimStream := new(pb.Claim_Stream)
|
||||
stream := new(pb.Stream)
|
||||
|
||||
pbClaim := new(pb.Claim)
|
||||
pbClaim.Type = claimStream
|
||||
claimStream.Stream = stream
|
||||
|
||||
return pbClaim
|
||||
}
|
||||
|
||||
func newChannelClaim() *pb.Claim {
|
||||
claimChannel := new(pb.Claim_Channel)
|
||||
channel := new(pb.Channel)
|
||||
|
||||
pbClaim := new(pb.Claim)
|
||||
pbClaim.Type = claimChannel
|
||||
claimChannel.Channel = channel
|
||||
|
||||
return pbClaim
|
||||
}
|
||||
|
||||
func setMetaData(claim *pb.Claim, author string, description string, language pb.Language_Language, license string,
|
||||
licenseURL *string, title string, thumbnail *string, nsfw bool) {
|
||||
claim.Title = title
|
||||
claim.Description = description
|
||||
|
||||
claim.GetStream().Author = author
|
||||
claim.Languages = []*pb.Language{{Language: language}}
|
||||
|
||||
if thumbnail != nil {
|
||||
source := new(pb.Source)
|
||||
source.Url = *thumbnail
|
||||
claim.Thumbnail = source
|
||||
}
|
||||
if nsfw {
|
||||
claim.Tags = []string{"mature"}
|
||||
}
|
||||
claim.GetStream().License = license
|
||||
if licenseURL != nil {
|
||||
claim.GetStream().LicenseUrl = *licenseURL
|
||||
}
|
||||
}
|
||||
|
||||
func migrateV1PBClaim(vClaim v1pb.Claim) (*pb.Claim, error) {
|
||||
if *vClaim.ClaimType == v1pb.Claim_streamType {
|
||||
return migrateV1PBStream(vClaim)
|
||||
}
|
||||
if *vClaim.ClaimType == v1pb.Claim_certificateType {
|
||||
return migrateV1PBChannel(vClaim)
|
||||
}
|
||||
return nil, errors.Err("Could not migrate v1 protobuf claim due to unknown type '%s'.", vClaim.ClaimType.String())
|
||||
}
|
||||
|
||||
func migrateV1PBStream(vClaim v1pb.Claim) (*pb.Claim, error) {
|
||||
claim := newStreamClaim()
|
||||
source := new(pb.Source)
|
||||
source.MediaType = vClaim.GetStream().GetSource().GetContentType()
|
||||
source.SdHash = vClaim.GetStream().GetSource().GetSource()
|
||||
claim.GetStream().Source = source
|
||||
md := vClaim.GetStream().GetMetadata()
|
||||
if md.GetFee() != nil {
|
||||
claim.GetStream().Fee = new(pb.Fee)
|
||||
claim.GetStream().GetFee().Amount = uint64(*md.GetFee().Amount * 100000000)
|
||||
claim.GetStream().GetFee().Address = md.GetFee().GetAddress()
|
||||
claim.GetStream().GetFee().Currency = pb.Fee_Currency(pb.Fee_Currency_value[md.GetFee().GetCurrency().String()])
|
||||
}
|
||||
if vClaim.GetStream().GetMetadata().GetNsfw() {
|
||||
claim.Tags = []string{"mature"}
|
||||
}
|
||||
thumbnailSource := new(pb.Source)
|
||||
thumbnailSource.Url = md.GetThumbnail()
|
||||
claim.Thumbnail = thumbnailSource
|
||||
language := pb.Language_Language(pb.Language_Language_value[md.GetLanguage().String()])
|
||||
claim.Languages = []*pb.Language{{Language: language}}
|
||||
claim.GetStream().LicenseUrl = md.GetLicenseUrl()
|
||||
claim.GetStream().License = md.GetLicense()
|
||||
claim.Title = md.GetTitle()
|
||||
claim.Description = md.GetDescription()
|
||||
claim.GetStream().Author = md.GetAuthor()
|
||||
|
||||
return claim, nil
|
||||
}
|
||||
|
||||
func migrateV1PBChannel(vClaim v1pb.Claim) (*pb.Claim, error) {
|
||||
claim := newChannelClaim()
|
||||
claim.GetChannel().PublicKey = vClaim.GetCertificate().PublicKey
|
||||
|
||||
return claim, nil
|
||||
}
|
||||
|
||||
func migrateV1Claim(vClaim V1Claim) (*pb.Claim, error) {
|
||||
pbClaim := newStreamClaim()
|
||||
//Stream
|
||||
// -->Universal
|
||||
setFee(vClaim.Fee, pbClaim)
|
||||
// -->MetaData
|
||||
language := pb.Language_Language(pb.Language_Language_value[vClaim.Language])
|
||||
setMetaData(pbClaim, vClaim.Author, vClaim.Description, language,
|
||||
vClaim.License, nil, vClaim.Title, vClaim.Thumbnail, false)
|
||||
// -->Source
|
||||
source := new(pb.Source)
|
||||
source.MediaType = vClaim.ContentType
|
||||
|
||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
source.SdHash = src
|
||||
pbClaim.GetStream().Source = source
|
||||
|
||||
return pbClaim, nil
|
||||
}
|
||||
|
||||
func migrateV2Claim(vClaim V2Claim) (*pb.Claim, error) {
|
||||
pbClaim := newStreamClaim()
|
||||
//Stream
|
||||
// -->Fee
|
||||
setFee(vClaim.Fee, pbClaim)
|
||||
// -->MetaData
|
||||
language := pb.Language_Language(pb.Language_Language_value[vClaim.Language])
|
||||
setMetaData(pbClaim, vClaim.Author, vClaim.Description, language,
|
||||
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
|
||||
// -->Source
|
||||
source := new(pb.Source)
|
||||
source.MediaType = vClaim.ContentType
|
||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
source.SdHash = src
|
||||
pbClaim.GetStream().Source = source
|
||||
|
||||
return pbClaim, nil
|
||||
}
|
||||
|
||||
func migrateV3Claim(vClaim V3Claim) (*pb.Claim, error) {
|
||||
pbClaim := newStreamClaim()
|
||||
//Stream
|
||||
// -->Fee
|
||||
setFee(vClaim.Fee, pbClaim)
|
||||
// -->MetaData
|
||||
language := pb.Language_Language(pb.Language_Language_value[vClaim.Language])
|
||||
setMetaData(pbClaim, vClaim.Author, vClaim.Description, language,
|
||||
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
|
||||
// -->Source
|
||||
source := new(pb.Source)
|
||||
source.MediaType = vClaim.ContentType
|
||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
source.SdHash = src
|
||||
pbClaim.GetStream().Source = source
|
||||
|
||||
return pbClaim, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
pbClaim.GetStream().Fee = new(pb.Fee)
|
||||
//Fee Settings
|
||||
pbClaim.GetStream().GetFee().Amount = uint64(amount * 100000000)
|
||||
pbClaim.GetStream().GetFee().Currency = currency
|
||||
pbClaim.GetStream().GetFee().Address = base58.Decode(address)
|
||||
}
|
||||
}
|
|
@ -1,11 +1,15 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
|
||||
"github.com/btcsuite/btcutil/base58"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
type valueTestPair struct {
|
||||
|
@ -51,7 +55,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"LBC",
|
||||
"bPwGA9h7uijoy5uAvzVPQw9QyLoYZehHJo",
|
||||
"application/octet-stream",
|
||||
"UNKNOWN_LANGUAGE", //"English" is not supported for conversion.
|
||||
"", //"English" is not supported for conversion.
|
||||
"bd94033d13f4f3908708701caf565bfa09cfadf2f34fadf4a73fb86b295d1b21a7e64805994e45b5fbc650f30bac4874",
|
||||
"/homerobert/lbry/speed.jpg",
|
||||
false,
|
||||
|
@ -68,7 +72,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"LBC",
|
||||
"bLVs3ifPruyZnpYmFfT2TLAmhqZvgjpQDa",
|
||||
"video/quicktime",
|
||||
"en",
|
||||
"language:en ",
|
||||
"dcc1bf28893a5037eab9e4a9cd7a4bfe6f76ad6c21970ea4ceee0122f502ef079657d4dca456b4be3249849c4e1868b8",
|
||||
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
|
||||
false,
|
||||
|
@ -85,7 +89,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"UNKNOWN_CURRENCY",
|
||||
"",
|
||||
"video/mp4",
|
||||
"en",
|
||||
"language:en ",
|
||||
"799a1de93b8e556d7f668103a6ffc48ac5fd6801dd4d89cae6773c80d81c283710fd4fd25ed68d0dbeee268f82914145",
|
||||
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
|
||||
false,
|
||||
|
@ -102,7 +106,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"USD",
|
||||
"bMHmZKZbPq6bPBEQFc8MXpiDhF9f7MVxMR",
|
||||
"video/mp4",
|
||||
"en",
|
||||
"language:en ",
|
||||
"2bd8d9dd1a218c7f56717e53fa510efd5a8c089ed1f2675a0f8d0b5b8bb3c1ed383cb9f3aeb9b891789761305293979a",
|
||||
"",
|
||||
false,
|
||||
|
@ -119,7 +123,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"LBC",
|
||||
"bVPqWwYfvjBHYBouuvknbQMXUZFvLdEs5M",
|
||||
"text/plain",
|
||||
"en",
|
||||
"language:en ",
|
||||
"7c21ee237324e5a50a3425620fe6cc400d3cccc05519867cda1b9c10a977194e31200414d87146bff470bab7f7d75478",
|
||||
"",
|
||||
false,
|
||||
|
@ -136,7 +140,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"USD",
|
||||
"bHSe3KAvtVSR4m6S11zduuF9XHtwscDjoE",
|
||||
"audio/mpeg",
|
||||
"en",
|
||||
"language:en ",
|
||||
"340e1dda0e8414c21fafbb1f28f2c8b384821fe0d1e2a7143a4810545e64e26a4105042d4d47dc9754b618ecdfe0d191",
|
||||
"http://i.imgur.com/lyKEHZc.jpg",
|
||||
false,
|
||||
|
@ -153,7 +157,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"LBC",
|
||||
"bRTxtCUpj6TvJHgWcRsGcHaFyrRLkkiXgG",
|
||||
"video/mp4",
|
||||
"en",
|
||||
"language:en ",
|
||||
"fc0dac5cfc526354963ff1769f6e739c4e42a0790420ffab9fa3b6401e93ae5a0515eff960f8c9c272907eda6fcba254",
|
||||
"",
|
||||
true,
|
||||
|
@ -184,40 +188,95 @@ func TestMigrationFromJSON(t *testing.T) {
|
|||
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().GetAuthor() != pair.Claim.Author {
|
||||
t.Error("Author mismatch: expected", pair.Claim.Author, "got", helper.Claim.GetStream().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.GetTitle() != pair.Claim.Title {
|
||||
t.Error("Title mismatch: expected", pair.Claim.Title, "got '", helper.Claim.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.GetDescription() != pair.Claim.Description {
|
||||
t.Error("Description mismatch: expected", pair.Claim.Description, "got '", helper.Claim.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().GetLicense() != pair.Claim.License {
|
||||
t.Error("License mismatch: expected", pair.Claim.License, "got", helper.Claim.GetStream().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().GetLicenseUrl() != pair.Claim.LicenseURL {
|
||||
t.Error("LicenseURL mismatch: expected", pair.Claim.LicenseURL, "got", helper.Claim.GetStream().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().GetFee().GetAmount() != uint64(pair.Claim.FeeAmount*100000000) {
|
||||
t.Error("Fee Amount mismatch: expected", pair.Claim.FeeAmount, "got", helper.Claim.GetStream().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())
|
||||
if helper.Claim.GetStream().GetFee().GetCurrency().String() != pair.Claim.FeeCurrency {
|
||||
t.Error("Fee Currency mismatch: expected", pair.Claim.FeeCurrency, "got", helper.Claim.GetStream().GetFee().GetCurrency())
|
||||
}
|
||||
hexaddress := base58.Encode(helper.Claim.GetStream().GetMetadata().GetFee().GetAddress())
|
||||
hexaddress := base58.Encode(helper.Claim.GetStream().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().GetSource().GetMediaType() != pair.Claim.ContentType {
|
||||
t.Error("ContentType mismatch: expected", pair.Claim.ContentType, "got", helper.Claim.GetStream().GetSource().GetMediaType())
|
||||
}
|
||||
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())
|
||||
if helper.Claim.GetLanguages()[0].String() != pair.Claim.Language {
|
||||
t.Error("Language mismatch: expected ", pair.Claim.Language, " got ", helper.Claim.GetLanguages()[0].String())
|
||||
}
|
||||
content := hex.EncodeToString(helper.Claim.GetStream().GetSource().GetSource())
|
||||
content := hex.EncodeToString(helper.Claim.GetStream().GetSource().GetSdHash())
|
||||
if content != pair.Claim.LbrySDHash {
|
||||
t.Error("Source mismatch: expected", pair.Claim.LbrySDHash, "got", content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrationFromV1YTSync(t *testing.T) {
|
||||
claimHex := "080110011aee04080112a604080410011a2b4865726520617265203520526561736f6e73204920e29da4efb88f204e657874636c6f7564207c20544c4722920346696e64206f7574206d6f72652061626f7574204e657874636c6f75643a2068747470733a2f2f6e657874636c6f75642e636f6d2f0a0a596f752063616e2066696e64206d65206f6e20746865736520736f6369616c733a0a202a20466f72756d733a2068747470733a2f2f666f72756d2e6865617679656c656d656e742e696f2f0a202a20506f64636173743a2068747470733a2f2f6f6666746f706963616c2e6e65740a202a2050617472656f6e3a2068747470733a2f2f70617472656f6e2e636f6d2f7468656c696e757867616d65720a202a204d657263683a2068747470733a2f2f746565737072696e672e636f6d2f73746f7265732f6f6666696369616c2d6c696e75782d67616d65720a202a205477697463683a2068747470733a2f2f7477697463682e74762f786f6e64616b0a202a20547769747465723a2068747470733a2f2f747769747465722e636f6d2f7468656c696e757867616d65720a0a2e2e2e0a68747470733a2f2f7777772e796f75747562652e636f6d2f77617463683f763d4672546442434f535f66632a0f546865204c696e75782047616d6572321c436f7079726967687465642028636f6e7461637420617574686f722938004a2968747470733a2f2f6265726b2e6e696e6a612f7468756d626e61696c732f4672546442434f535f666352005a001a41080110011a30040e8ac6e89c061f982528c23ad33829fd7146435bf7a4cc22f0bff70c4fe0b91fd36da9a375e3e1c171db825bf5d1f32209766964656f2f6d70342a5c080110031a4062b2dd4c45e364030fbfad1a6fefff695ebf20ea33a5381b947753e2a0ca359989a5cc7d15e5392a0d354c0b68498382b2701b22c03beb8dcb91089031b871e72214feb61536c007cdf4faeeaab4876cb397feaf6b51"
|
||||
claim, err := DecodeClaimHex(claimHex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, claim.GetTitle() == "Here are 5 Reasons I ❤️ Nextcloud | TLG")
|
||||
assert.Assert(t, claim.GetDescription() == "Find out more about Nextcloud: https://nextcloud.com/\n\nYou can find me on these socials:\n * Forums: https://forum.heavyelement.io/\n * Podcast: https://offtopical.net\n * Patreon: https://patreon.com/thelinuxgamer\n * Merch: https://teespring.com/stores/official-linux-gamer\n * Twitch: https://twitch.tv/xondak\n * Twitter: https://twitter.com/thelinuxgamer\n\n...\nhttps://www.youtube.com/watch?v=FrTdBCOS_fc")
|
||||
assert.Assert(t, claim.GetStream().GetLicense() == "Copyrighted (contact author)")
|
||||
assert.Assert(t, claim.GetStream().GetAuthor() == "The Linux Gamer")
|
||||
//?assert.Assert(t, claim.GetStream().GetLanguages()[0])
|
||||
assert.Assert(t, claim.GetStream().GetSource().GetMediaType() == "video/mp4")
|
||||
assert.Assert(t, claim.GetThumbnail().GetUrl() == "https://berk.ninja/thumbnails/FrTdBCOS_fc")
|
||||
sdHashBytes, err := hex.DecodeString("040e8ac6e89c061f982528c23ad33829fd7146435bf7a4cc22f0bff70c4fe0b91fd36da9a375e3e1c171db825bf5d1f3")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, bytes.Equal(claim.GetStream().GetSource().GetSdHash(), sdHashBytes))
|
||||
|
||||
channelHex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a034200043878b1edd4a1373149909ef03f4339f6da9c2bd2214c040fd2e530463ffe66098eca14fc70b50ff3aefd106049a815f595ed5a13eda7419ad78d9ed7ae473f17"
|
||||
channel, err := DecodeClaimHex(channelHex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
pubKeyBytes, err := hex.DecodeString("3056301006072a8648ce3d020106052b8104000a034200043878b1edd4a1373149909ef03f4339f6da9c2bd2214c040fd2e530463ffe66098eca14fc70b50ff3aefd106049a815f595ed5a13eda7419ad78d9ed7ae473f17")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, bytes.Equal(pubKeyBytes, channel.GetChannel().GetPublicKey()))
|
||||
}
|
||||
|
||||
func TestMigrationFromV1UnsignedWithFee(t *testing.T) {
|
||||
claimHex := "080110011ad6010801127c080410011a08727067206d69646922046d6964692a08727067206d696469322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a19553f00bc139bbf40de425f94d51fffb34c1bea6d9171cd374c25000070414a0052005a001a54080110011a301f41eb0312aa7e8a5ce49349bc77d811da975833719d751523b19f123fc3d528d6a94e3446ccddb7b9329f27a9cad7e3221c6170706c69636174696f6e2f782d7a69702d636f6d70726573736564"
|
||||
claim, err := DecodeClaimHex(claimHex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, claim.GetTitle() == "rpg midi")
|
||||
assert.Assert(t, claim.GetDescription() == "midi")
|
||||
assert.Assert(t, claim.GetStream().GetLicense() == "Creative Commons Attribution 4.0 International")
|
||||
assert.Assert(t, claim.GetStream().GetAuthor() == "rpg midi")
|
||||
//assert.Assert(t, claim.GetStream().GetLanguage() == "en")
|
||||
assert.Assert(t, claim.GetStream().GetSource().GetMediaType() == "application/x-zip-compressed")
|
||||
sdHashBytes, err := hex.DecodeString("1f41eb0312aa7e8a5ce49349bc77d811da975833719d751523b19f123fc3d528d6a94e3446ccddb7b9329f27a9cad7e3")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, bytes.Equal(claim.GetStream().GetSource().GetSdHash(), sdHashBytes))
|
||||
feeAddressBytes, err := address.DecodeAddress("bJUQ9MxS9N6M29zsA5GTpVSDzsnPjMBBX9", "lbrycrd_main")
|
||||
assert.Assert(t, bytes.Equal(claim.GetStream().GetFee().GetAddress(), feeAddressBytes[:]))
|
||||
assert.Assert(t, claim.GetStream().GetFee().GetAmount() == 1500000000)
|
||||
assert.Assert(t, claim.GetStream().GetFee().GetCurrency().String() == "LBC")
|
||||
|
||||
}
|
|
@ -3,7 +3,7 @@ package claim
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/lbryio/lbry.go/errors"
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
)
|
||||
|
||||
// V1Claim is the first version of claim metadata used by lbry.
|
90
schema/claim/serialization.go
Normal file
90
schema/claim/serialization.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
legacy "github.com/lbryio/types/v1/go"
|
||||
pb "github.com/lbryio/types/v2/go"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
func (c *ClaimHelper) serialized() ([]byte, error) {
|
||||
serialized := c.String()
|
||||
if serialized == "" {
|
||||
return nil, errors.Err("not initialized")
|
||||
}
|
||||
|
||||
if c.LegacyClaim != nil {
|
||||
return proto.Marshal(c.getLegacyProtobuf())
|
||||
}
|
||||
|
||||
return proto.Marshal(c.getProtobuf())
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) getProtobuf() *pb.Claim {
|
||||
claim := &pb.Claim{
|
||||
Title: c.GetTitle(),
|
||||
Description: c.GetDescription(),
|
||||
Thumbnail: c.GetThumbnail(),
|
||||
Tags: c.GetTags(),
|
||||
Languages: c.GetLanguages(),
|
||||
Locations: c.GetLocations(),
|
||||
}
|
||||
if c.GetChannel() != nil {
|
||||
claim.Type = &pb.Claim_Channel{Channel: c.GetChannel()}
|
||||
} else if c.GetStream() != nil {
|
||||
claim.Type = &pb.Claim_Stream{Stream: c.GetStream()}
|
||||
} else if c.GetCollection() != nil {
|
||||
claim.Type = &pb.Claim_Collection{Collection: c.GetCollection()}
|
||||
} else if c.GetRepost() != nil {
|
||||
claim.Type = &pb.Claim_Repost{Repost: c.GetRepost()}
|
||||
}
|
||||
|
||||
return claim
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) getLegacyProtobuf() *legacy.Claim {
|
||||
v := c.LegacyClaim.GetVersion()
|
||||
t := c.LegacyClaim.GetClaimType()
|
||||
return &legacy.Claim{
|
||||
Version: &v,
|
||||
ClaimType: &t,
|
||||
Stream: c.LegacyClaim.GetStream(),
|
||||
Certificate: c.LegacyClaim.GetCertificate(),
|
||||
PublisherSignature: c.LegacyClaim.GetPublisherSignature()}
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) serializedHexString() (string, error) {
|
||||
serialized, err := c.serialized()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
serialized_hex := hex.EncodeToString(serialized)
|
||||
return serialized_hex, nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) serializedNoSignature() ([]byte, error) {
|
||||
if c.String() == "" {
|
||||
return nil, errors.Err("not initialized")
|
||||
}
|
||||
if c.Signature == nil {
|
||||
serialized, err := c.serialized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return serialized, nil
|
||||
} else {
|
||||
if c.LegacyClaim != nil {
|
||||
clone := &legacy.Claim{}
|
||||
proto.Merge(clone, c.getLegacyProtobuf())
|
||||
proto.ClearAllExtensions(clone.PublisherSignature)
|
||||
clone.PublisherSignature = nil
|
||||
return proto.Marshal(clone)
|
||||
}
|
||||
clone := &pb.Claim{}
|
||||
proto.Merge(clone, c.getProtobuf())
|
||||
return proto.Marshal(clone)
|
||||
}
|
||||
}
|
112
schema/claim/sign.go
Normal file
112
schema/claim/sign.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
func Sign(privKey btcec.PrivateKey, channel ClaimHelper, claim ClaimHelper, k string) (*Signature, error) {
|
||||
if channel.GetChannel() == nil {
|
||||
return nil, errors.Err("claim as channel is not of type channel")
|
||||
}
|
||||
if claim.LegacyClaim != nil {
|
||||
return claim.signV1(privKey, channel, k)
|
||||
}
|
||||
|
||||
return claim.sign(privKey, channel, k)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) sign(privKey btcec.PrivateKey, channel ClaimHelper, firstInputTxID string) (*Signature, error) {
|
||||
|
||||
txidBytes, err := hex.DecodeString(firstInputTxID)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
metadataBytes, err := c.serialized()
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
var digest []byte
|
||||
digest = append(digest, txidBytes...)
|
||||
digest = append(digest, c.ClaimID...)
|
||||
digest = append(digest, metadataBytes...)
|
||||
hash := sha256.Sum256(digest)
|
||||
hashBytes := make([]byte, len(hash))
|
||||
for i, b := range hash {
|
||||
hashBytes[i] = b
|
||||
}
|
||||
|
||||
sig, err := privKey.Sign(hashBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
return &Signature{*sig}, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) signV1(privKey btcec.PrivateKey, channel ClaimHelper, claimAddress string) (*Signature, error) {
|
||||
metadataBytes, err := c.serializedNoSignature()
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
addressBytes, err := address.DecodeAddress(claimAddress, "lbrycrd_main")
|
||||
if err != nil {
|
||||
return nil, errors.Prefix("V1 signing requires claim address and the decode failed with: ", err)
|
||||
}
|
||||
|
||||
var digest []byte
|
||||
|
||||
address := make([]byte, len(addressBytes))
|
||||
for i, b := range addressBytes {
|
||||
address[i] = b
|
||||
}
|
||||
|
||||
digest = append(digest, address...)
|
||||
digest = append(digest, metadataBytes...)
|
||||
digest = append(digest, channel.ClaimID...)
|
||||
|
||||
hash := sha256.Sum256(digest)
|
||||
hashBytes := make([]byte, len(hash))
|
||||
for i, b := range hash {
|
||||
hashBytes[i] = b
|
||||
}
|
||||
|
||||
sig, err := privKey.Sign(hashBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
return &Signature{*sig}, nil
|
||||
}
|
||||
|
||||
type Signature struct {
|
||||
btcec.Signature
|
||||
}
|
||||
|
||||
func (s *Signature) LBRYSDKEncode() ([]byte, error) {
|
||||
if s.R == nil || s.S == nil {
|
||||
return nil, errors.Err("invalid signature, both S & R are nil")
|
||||
}
|
||||
rBytes := s.R.Bytes()
|
||||
sBytes := s.S.Bytes()
|
||||
|
||||
return append(rBytes, sBytes...), nil
|
||||
}
|
||||
|
||||
// rev reverses a byte slice. useful for switching endian-ness
|
||||
func reverseBytes(b []byte) []byte {
|
||||
r := make([]byte, len(b))
|
||||
for left, right := 0, len(b)-1; left < right; left, right = left+1, right-1 {
|
||||
r[left], r[right] = b[right], b[left]
|
||||
}
|
||||
return r
|
||||
}
|
137
schema/claim/sign_test.go
Normal file
137
schema/claim/sign_test.go
Normal file
|
@ -0,0 +1,137 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
privateKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
channel := &ClaimHelper{newChannelClaim(), nil, nil, NoSig, nil, nil}
|
||||
pubkeyBytes, err := PublicKeyToDER(privateKey.PubKey())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
channel.GetChannel().PublicKey = pubkeyBytes
|
||||
claimID := "cf3f7c898af87cc69b06a6ac7899efb9a4878fdb" //Fake
|
||||
txid := "4c1df9e022e396859175f9bfa69b38e444db10fb53355fa99a0989a83bcdb82f" //Fake
|
||||
claimIDHexBytes, err := hex.DecodeString(claimID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
claim := &ClaimHelper{newStreamClaim(), nil, reverseBytes(claimIDHexBytes), WithSig, nil, nil}
|
||||
claim.Claim.Title = "Test title"
|
||||
claim.Claim.Description = "Test description"
|
||||
sig, err := Sign(*privateKey, *channel, *claim, txid)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
signatureBytes, err := sig.LBRYSDKEncode()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
claim.Signature = signatureBytes
|
||||
|
||||
rawChannel, err := channel.CompileValue()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
rawClaim, err := claim.CompileValue()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
channel, err = DecodeClaimBytes(rawChannel, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
claim, err = DecodeClaimBytes(rawClaim, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
valid, err := claim.ValidateClaimSignature(channel, txid, claimID, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Assert(t, valid, "could not verify signature")
|
||||
|
||||
}
|
||||
|
||||
func TestSignWithV1Channel(t *testing.T) {
|
||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
channel, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
privateKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
pubkeyBytes, err := PublicKeyToDER(privateKey.PubKey())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
channel.GetChannel().PublicKey = pubkeyBytes
|
||||
|
||||
claimID := "251305ca93d4dbedb50dceb282ebcb7b07b7ac64"
|
||||
txid := "4c1df9e022e396859175f9bfa69b38e444db10fb53355fa99a0989a83bcdb82f" //Fake
|
||||
claimIDHexBytes, err := hex.DecodeString(claimID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
claim := &ClaimHelper{newStreamClaim(), nil, reverseBytes(claimIDHexBytes), WithSig, nil, nil}
|
||||
claim.Claim.Title = "Test title"
|
||||
claim.Claim.Description = "Test description"
|
||||
sig, err := Sign(*privateKey, *channel, *claim, txid)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
signatureBytes, err := sig.LBRYSDKEncode()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
claim.Signature = signatureBytes
|
||||
compiledClaim, err := claim.CompileValue()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
claim, err = DecodeClaimBytes(compiledClaim, "lbrycrd_main")
|
||||
|
||||
valid, err := claim.ValidateClaimSignature(channel, txid, claimID, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Assert(t, valid, "could not verify signature")
|
||||
|
||||
}
|
128
schema/claim/validator.go
Normal file
128
schema/claim/validator.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
)
|
||||
|
||||
type publicKeyInfo struct {
|
||||
Raw asn1.RawContent
|
||||
Algorithm pkix.AlgorithmIdentifier
|
||||
PublicKey asn1.BitString
|
||||
}
|
||||
|
||||
const SECP256k1 = "SECP256k1"
|
||||
|
||||
//const NIST256p = "NIST256p"
|
||||
//const NIST384p = "NIST384p"
|
||||
|
||||
func getClaimSignatureDigest(bytes ...[]byte) [32]byte {
|
||||
|
||||
var combined []byte
|
||||
for _, b := range bytes {
|
||||
combined = append(combined, b...)
|
||||
}
|
||||
digest := sha256.Sum256(combined)
|
||||
return [32]byte(digest)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) VerifyDigest(certificate *ClaimHelper, signature [64]byte, digest [32]byte) bool {
|
||||
if certificate == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
R := &big.Int{}
|
||||
S := &big.Int{}
|
||||
R.SetBytes(signature[0:32])
|
||||
S.SetBytes(signature[32:64])
|
||||
pk, err := certificate.GetPublicKey()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ecdsa.Verify(pk.ToECDSA(), digest[:], R, S)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateClaimSignature(certificate *ClaimHelper, k string, certificateId string, blockchainName string) (bool, error) {
|
||||
if c.LegacyClaim != nil {
|
||||
return c.validateV1ClaimSignature(certificate, k, certificateId, blockchainName)
|
||||
}
|
||||
|
||||
return c.validateClaimSignature(certificate, k, certificateId, blockchainName)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) validateClaimSignature(certificate *ClaimHelper, firstInputTxHash, certificateId string, blockchainName string) (bool, error) {
|
||||
certificateIdSlice, err := hex.DecodeString(certificateId)
|
||||
if err != nil {
|
||||
return false, errors.Err(err)
|
||||
}
|
||||
certificateIdSlice = reverseBytes(certificateIdSlice)
|
||||
firstInputTxIDBytes, err := hex.DecodeString(firstInputTxHash)
|
||||
if err != nil {
|
||||
return false, errors.Err(err)
|
||||
}
|
||||
|
||||
signature := c.Signature
|
||||
if signature == nil {
|
||||
return false, errors.Err("claim does not have a signature")
|
||||
}
|
||||
signatureBytes := [64]byte{}
|
||||
for i, b := range signature {
|
||||
signatureBytes[i] = b
|
||||
}
|
||||
|
||||
claimDigest := getClaimSignatureDigest(firstInputTxIDBytes, certificateIdSlice, c.Payload)
|
||||
return c.VerifyDigest(certificate, signatureBytes, claimDigest), nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) validateV1ClaimSignature(certificate *ClaimHelper, claimAddy string, certificateId string, blockchainName string) (bool, error) {
|
||||
addressBytes, err := address.DecodeAddress(claimAddy, blockchainName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
//For V1 claim_id was incorrectly stored for claim signing.
|
||||
// So the bytes are not reversed like they are supposed to be (Endianess)
|
||||
certificateIdSlice, err := hex.DecodeString(certificateId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
signature := c.Signature
|
||||
if signature == nil {
|
||||
return false, errors.Err("claim does not have a signature")
|
||||
}
|
||||
signatureBytes := [64]byte{}
|
||||
for i := range signatureBytes {
|
||||
signatureBytes[i] = signature[i]
|
||||
}
|
||||
|
||||
claimAddress, err := address.ValidateAddress(addressBytes, blockchainName)
|
||||
if err != nil {
|
||||
return false, errors.Err("invalid address")
|
||||
}
|
||||
|
||||
serializedNoSig, err := c.serializedNoSignature()
|
||||
if err != nil {
|
||||
return false, errors.Err("serialization error")
|
||||
}
|
||||
|
||||
claimDigest := getClaimSignatureDigest(claimAddress[:], serializedNoSig, certificateIdSlice)
|
||||
return c.VerifyDigest(certificate, signatureBytes, claimDigest), nil
|
||||
}
|
||||
|
||||
func GetOutpointHash(txid string, vout uint32) (string, error) {
|
||||
txidBytes, err := hex.DecodeString(txid)
|
||||
if err != nil {
|
||||
return "", errors.Err(err)
|
||||
}
|
||||
var voutBytes = make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(voutBytes, vout)
|
||||
return hex.EncodeToString(append(reverseBytes(txidBytes), voutBytes...)), nil
|
||||
}
|
|
@ -2,14 +2,22 @@ package claim
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func TestValidateClaimSignature(t *testing.T) {
|
||||
func TestV1ValidateClaimSignature(t *testing.T) {
|
||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
signed_claim_hex := "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
|
||||
signed_claim, _ := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
cert_claim, _ := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
signed_claim, err := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cert_claim, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
claim_addr := "bSkUov7HMWpYBiXackDwRnR5ishhGHvtJt"
|
||||
cert_id := "251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
|
@ -23,12 +31,18 @@ func TestValidateClaimSignature(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFailToValidateClaimSignature(t *testing.T) {
|
||||
func TestV1FailToValidateClaimSignature(t *testing.T) {
|
||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
signed_claim_hex := "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
|
||||
signed_claim, _ := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
cert_claim, _ := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
signed_claim, err := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cert_claim, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
claim_addr := "bSkUov7HMWpYBiXackDwRnR5ishhGHvtJt"
|
||||
cert_id := "251305ca93d4dbedb50dceb282ebcb7b07b7ac64"
|
||||
|
@ -41,3 +55,40 @@ func TestFailToValidateClaimSignature(t *testing.T) {
|
|||
t.Error("failed to validate signature:", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestV2ValidateClaimSignature(t *testing.T) {
|
||||
cert_claim_hex := "00125a0a583056301006072a8648ce3d020106052b8104000a034200045a0343c155302280da01ae0001b7295241eb03c42a837acf92ccb9680892f7db50fd1d3c14b28bb594e304f05fc4ae7c1f222a85d1d1a3461b3cfb9906f66cb5"
|
||||
signed_claim_hex := "015cb78e424a34fbf79b67f9107430427aa62373e69b4998a29ecec8f14a9e0a213a043ced8064c069d7e464b5fd3ccb92b45bd59b15c0e1bb27e3c366d43f86a9a6b5ad42647a1aad69a73ac50b19ae3ec978c2c70aa2010a99010a301c662f19abc461e7eddecf165adfa7fca569e209773f3db31241c1e297f0a8d5b3e4768828b065fbeb1d6776f61073f6121b3031202d20556e6d6173746572656420496d70756c7365732e377a187a22146170706c69636174696f6e2f782d6578742d377a32302eb61ea475017e28c013616a56c1219ba90dc35fffff453d9675146f648f66634e0d1516528d37aba9f5801229d9f2181a044e6f6e6542087465737420707562520062020801"
|
||||
|
||||
signed_claim, err := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cert_claim, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
firstInputTxHash, err := GetOutpointHash("becb96a4a2e66bd24f083772fe9da904654ea9b5f07cc5bfbee233355911ddb1", uint32(0))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cert_id := "e67323a67a42307410f9679bf7fb344a428eb75c"
|
||||
|
||||
result, err := signed_claim.ValidateClaimSignature(cert_claim, firstInputTxHash, cert_id, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if result != true {
|
||||
t.Error("failed to validate signature:", result)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetOutpointHash(t *testing.T) {
|
||||
hash, err := GetOutpointHash("dc3dcf2f94d3c91e454ac2474802e20f26b30705372dda43890c811d918aef64", 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, hash == "64ef8a911d810c8943da2d370507b3260fe2024847c24a451ec9d3942fcf3ddc01000000", uint(1))
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
from ctypes import *
|
||||
|
||||
|
||||
class _GoString(Structure):
|
||||
_fields_ = [
|
||||
("p", c_char_p),
|
||||
("n", c_longlong)
|
||||
]
|
||||
|
||||
|
||||
def GoString(s):
|
||||
if not isinstance(s, (str, unicode)):
|
||||
raise TypeError("invalid type: %s" % str(type(s)))
|
||||
x = str(s)
|
||||
return _GoString(x, len(x))
|
||||
|
||||
|
||||
def GoBinding(library, *argTypes):
|
||||
"""
|
||||
Get a binding to a go function of the same name in the given .so
|
||||
The python function itself is not run, and can return or pass
|
||||
|
||||
:param argTypes: *parameter types
|
||||
"""
|
||||
|
||||
lib = cdll.LoadLibrary(library)
|
||||
|
||||
def inner(fn):
|
||||
_types = {
|
||||
str: _GoString
|
||||
}
|
||||
|
||||
_getters = {
|
||||
str: GoString
|
||||
}
|
||||
|
||||
for v in argTypes:
|
||||
if not isinstance(v, type):
|
||||
raise TypeError("invalid argument type")
|
||||
if v not in _types:
|
||||
raise TypeError("type does not have a mapping: %s" % str(type(v)))
|
||||
|
||||
_go_func = getattr(lib, fn.__name__)
|
||||
_go_func.argtypes = [_types[v] for v in argTypes]
|
||||
|
||||
def _wrap(*args):
|
||||
_args = [_getters[arg_type](arg) for arg_type, arg in zip(argTypes, args)]
|
||||
return _go_func(*tuple(_args))
|
||||
return _wrap
|
||||
return inner
|
||||
|
||||
|
||||
@GoBinding("./lbryschema-python-binding.so", str, str, str, str)
|
||||
def VerifySignature(claim, certificate, claim_address, certificate_id):
|
||||
pass
|
||||
|
||||
|
||||
cert_claim_hex = "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
signed_claim_hex = "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
claim_addr = "bSkUov7HMWpYBiXackDwRnR5ishhGHvtJt"
|
||||
cert_id = "251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
import time
|
||||
from lbryschema.decode import smart_decode
|
||||
|
||||
cd = smart_decode(signed_claim_hex)
|
||||
certd = smart_decode(cert_claim_hex)
|
||||
|
||||
|
||||
def clock_lbryschema_python(n=10.0):
|
||||
start = time.time()
|
||||
for i in range(int(n)):
|
||||
assert cd.validate_signature(claim_addr, certd)
|
||||
if i % 10 == 0:
|
||||
print i
|
||||
avg = float(time.time() - start) / n
|
||||
return 1.0 / avg
|
||||
|
||||
|
||||
def clock_lbryschema_go(n=100.0):
|
||||
start = time.time()
|
||||
for i in range(int(n)):
|
||||
assert VerifySignature(signed_claim_hex, cert_claim_hex, claim_addr, cert_id)
|
||||
if i % 10 == 0:
|
||||
print i
|
||||
avg = float(time.time() - start) / n
|
||||
return 1.0 / avg
|
||||
|
||||
print "Start"
|
||||
print "%f validations / second with python" % clock_lbryschema_python()
|
||||
print "%f validations / second with go binding" % clock_lbryschema_go()
|
||||
|
Loading…
Reference in a new issue