Commit 011cd41b authored by Alessandro Sorniotti's avatar Alessandro Sorniotti
Browse files

[FAB-1392] - Use bytes for headers



This change set ensures that the protobuf representation for headers be in
bytes. This makes sure that if ever protobuf marshalling is non-deterministic,
we do not have problems because whenever we hash a header, we do that over
the serialized version we receive.

Change-Id: I838e0d5dec2f79f88fab63d92bdfb51d92c2f069
Signed-off-by: default avatarAlessandro Sorniotti <ale.linux@sopit.net>
parent 008ee851
......@@ -92,9 +92,9 @@ func makeConfigUpdateEnvelope(chainID string, configPairs ...*configPair) *cb.En
return &cb.Envelope{
Payload: utils.MarshalOrPanic(&cb.Payload{
Header: &cb.Header{
ChannelHeader: &cb.ChannelHeader{
ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
Type: int32(cb.HeaderType_CONFIG_UPDATE),
},
}),
},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(config),
......
......@@ -154,11 +154,16 @@ func envelopeToConfigUpdate(configtx *cb.Envelope) (*cb.ConfigUpdateEnvelope, er
return nil, err
}
if payload.Header == nil || payload.Header.ChannelHeader == nil {
return nil, fmt.Errorf("Envelope must have ChannelHeader")
if payload.Header == nil /* || payload.Header.ChannelHeader == nil */ {
return nil, fmt.Errorf("Envelope must have a Header")
}
if payload.Header == nil || payload.Header.ChannelHeader.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return nil, fmt.Errorf("Invalid ChannelHeader")
}
if chdr.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
return nil, fmt.Errorf("Not a tx of type CONFIG_UPDATE")
}
......
......@@ -207,5 +207,9 @@ func extractTxID(txEnvelopBytes []byte) (string, error) {
if err != nil {
return "", nil
}
return txPayload.Header.ChannelHeader.TxId, nil
chdr, err := utils.UnmarshalChannelHeader(txPayload.Header.ChannelHeader)
if err != nil {
return "", err
}
return chdr.TxId, nil
}
......@@ -75,11 +75,11 @@ func TestNewTxValidator_DuplicateTransactions(t *testing.T) {
// Create simeple endorsement transaction
payload := &common.Payload{
Header: &common.Header{
ChannelHeader: &common.ChannelHeader{
ChannelHeader: utils.MarshalOrPanic(&common.ChannelHeader{
TxId: "simple_txID", // Fake txID
Type: int32(common.HeaderType_ENDORSER_TRANSACTION),
ChannelId: util2.GetTestChainID(),
},
}),
},
Data: []byte("test"),
}
......
......@@ -118,17 +118,23 @@ func (v *txValidator) Validate(block *common.Block) error {
continue
}
chain := payload.Header.ChannelHeader.ChannelId
logger.Debug("Transaction is for chain %s", chain)
chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
logger.Warning("Could not unmarshal channel header, err %s, skipping", err)
continue
}
if !v.chainExists(chain) {
logger.Errorf("Dropping transaction for non-existent chain %s", chain)
channel := chdr.ChannelId
logger.Debug("Transaction is for chain %s", channel)
if !v.chainExists(channel) {
logger.Errorf("Dropping transaction for non-existent chain %s", channel)
continue
}
if common.HeaderType(payload.Header.ChannelHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
// Check duplicate transactions
txID := payload.Header.ChannelHeader.TxId
txID := chdr.TxId
if _, err := v.support.Ledger().GetTransactionByID(txID); err == nil {
logger.Warning("Duplicate transaction found, ", txID, ", skipping")
continue
......@@ -141,7 +147,7 @@ func (v *txValidator) Validate(block *common.Block) error {
logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err)
continue
}
} else if common.HeaderType(payload.Header.ChannelHeader.Type) == common.HeaderType_CONFIG {
} else if common.HeaderType(chdr.Type) == common.HeaderType_CONFIG {
configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
if err != nil {
err := fmt.Errorf("Error unmarshaling config which passed initial validity checks: %s", err)
......@@ -154,7 +160,7 @@ func (v *txValidator) Validate(block *common.Block) error {
logger.Critical(err)
return err
}
logger.Debugf("config transaction received for chain %s", chain)
logger.Debugf("config transaction received for chain %s", channel)
}
if _, err := proto.Marshal(env); err != nil {
......@@ -178,8 +184,13 @@ func (v *txValidator) Validate(block *common.Block) error {
}
func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []byte) error {
chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return err
}
// Chain ID
chainID := payload.Header.ChannelHeader.ChannelId
chainID := chdr.ChannelId
if chainID == "" {
err := fmt.Errorf("transaction header does not contain an chain ID")
logger.Errorf("%s", err)
......@@ -187,8 +198,7 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
}
// Get transaction id
txid := payload.Header.ChannelHeader.TxId
logger.Info("[XXX remove me XXX] Transaction type,", common.HeaderType(payload.Header.ChannelHeader.Type))
txid := chdr.TxId
if txid == "" {
err := fmt.Errorf("transaction header does not contain transaction ID")
logger.Errorf("%s", err)
......
......@@ -36,14 +36,14 @@ func TestValidateConfigTx(t *testing.T) {
updateResult := &cb.Envelope{
Payload: utils.MarshalOrPanic(&cb.Payload{Header: &cb.Header{
ChannelHeader: &cb.ChannelHeader{
ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
Type: int32(cb.HeaderType_CONFIG),
ChannelId: chainID,
},
SignatureHeader: &cb.SignatureHeader{
}),
SignatureHeader: utils.MarshalOrPanic(&cb.SignatureHeader{
Creator: signerSerialized,
Nonce: utils.CreateNonceOrPanic(),
},
}),
},
Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{
LastUpdate: chCrtEnv,
......
......@@ -79,13 +79,13 @@ func ValidateProposalMessage(signedProp *pb.SignedProposal) (*pb.Proposal, *comm
}
// validate the header
err = validateCommonHeader(hdr)
chdr, shdr, err := validateCommonHeader(hdr)
if err != nil {
return nil, nil, nil, err
}
// validate the signature
err = checkSignatureFromCreator(hdr.SignatureHeader.Creator, signedProp.Signature, signedProp.ProposalBytes, hdr.ChannelHeader.ChannelId)
err = checkSignatureFromCreator(shdr.Creator, signedProp.Signature, signedProp.ProposalBytes, chdr.ChannelId)
if err != nil {
return nil, nil, nil, err
}
......@@ -96,15 +96,15 @@ func ValidateProposalMessage(signedProp *pb.SignedProposal) (*pb.Proposal, *comm
// This check is needed to ensure that the lookup into the ledger
// for the same TxID catches duplicates.
err = utils.CheckProposalTxID(
hdr.ChannelHeader.TxId,
hdr.SignatureHeader.Nonce,
hdr.SignatureHeader.Creator)
chdr.TxId,
shdr.Nonce,
shdr.Creator)
if err != nil {
return nil, nil, nil, err
}
// continue the validation in a way that depends on the type specified in the header
switch common.HeaderType(hdr.ChannelHeader.Type) {
switch common.HeaderType(chdr.Type) {
case common.HeaderType_CONFIG:
//which the types are different the validation is the same
//viz, validate a proposal to a chaincode. If we need other
......@@ -121,7 +121,7 @@ func ValidateProposalMessage(signedProp *pb.SignedProposal) (*pb.Proposal, *comm
return prop, hdr, chaincodeHdrExt, err
default:
//NOTE : we proably need a case
return nil, nil, nil, fmt.Errorf("Unsupported proposal type %d", common.HeaderType(hdr.ChannelHeader.Type))
return nil, nil, nil, fmt.Errorf("Unsupported proposal type %d", common.HeaderType(chdr.Type))
}
}
......@@ -220,22 +220,32 @@ func validateChannelHeader(cHdr *common.ChannelHeader) error {
}
// checks for a valid Header
func validateCommonHeader(hdr *common.Header) error {
func validateCommonHeader(hdr *common.Header) (*common.ChannelHeader, *common.SignatureHeader, error) {
if hdr == nil {
return fmt.Errorf("Nil header")
return nil, nil, fmt.Errorf("Nil header")
}
err := validateChannelHeader(hdr.ChannelHeader)
chdr, err := utils.UnmarshalChannelHeader(hdr.ChannelHeader)
if err != nil {
return err
return nil, nil, err
}
err = validateSignatureHeader(hdr.SignatureHeader)
shdr, err := utils.GetSignatureHeader(hdr.SignatureHeader)
if err != nil {
return err
return nil, nil, err
}
return nil
err = validateChannelHeader(chdr)
if err != nil {
return nil, nil, err
}
err = validateSignatureHeader(shdr)
if err != nil {
return nil, nil, err
}
return chdr, shdr, nil
}
// validateConfigTransaction validates the payload of a
......@@ -319,14 +329,10 @@ func validateEndorserTransaction(data []byte, hdr *common.Header) error {
// build the original header by stitching together
// the common ChannelHeader and the per-action SignatureHeader
hdrOrig := &common.Header{ChannelHeader: hdr.ChannelHeader, SignatureHeader: sHdr}
hdrBytes, err := utils.GetBytesHeader(hdrOrig) // FIXME: here we hope that hdrBytes will be the same one that the endorser had
if err != nil {
return err
}
hdrOrig := &common.Header{ChannelHeader: hdr.ChannelHeader, SignatureHeader: act.Header}
// compute proposalHash
pHash, err := utils.GetProposalHash2(hdrBytes, cap.ChaincodeProposalPayload)
pHash, err := utils.GetProposalHash2(hdrOrig, cap.ChaincodeProposalPayload)
if err != nil {
return err
}
......@@ -358,13 +364,13 @@ func ValidateTransaction(e *common.Envelope) (*common.Payload, error) {
putilsLogger.Infof("Header is %s", payload.Header)
// validate the header
err = validateCommonHeader(payload.Header)
chdr, shdr, err := validateCommonHeader(payload.Header)
if err != nil {
return nil, err
}
// validate the signature in the envelope
err = checkSignatureFromCreator(payload.Header.SignatureHeader.Creator, e.Signature, e.Payload, payload.Header.ChannelHeader.ChannelId)
err = checkSignatureFromCreator(shdr.Creator, e.Signature, e.Payload, chdr.ChannelId)
if err != nil {
return nil, err
}
......@@ -372,15 +378,15 @@ func ValidateTransaction(e *common.Envelope) (*common.Payload, error) {
// TODO: ensure that creator can transact with us (some ACLs?) which set of APIs is supposed to give us this info?
// continue the validation in a way that depends on the type specified in the header
switch common.HeaderType(payload.Header.ChannelHeader.Type) {
switch common.HeaderType(chdr.Type) {
case common.HeaderType_ENDORSER_TRANSACTION:
// Verify that the transaction ID has been computed properly.
// This check is needed to ensure that the lookup into the ledger
// for the same TxID catches duplicates.
err = utils.CheckProposalTxID(
payload.Header.ChannelHeader.TxId,
payload.Header.SignatureHeader.Nonce,
payload.Header.SignatureHeader.Creator)
chdr.TxId,
shdr.Nonce,
shdr.Creator)
if err != nil {
return nil, err
}
......@@ -396,6 +402,6 @@ func ValidateTransaction(e *common.Envelope) (*common.Payload, error) {
putilsLogger.Infof("ValidateTransactionEnvelope returns err %s", err)
return payload, err
default:
return nil, fmt.Errorf("Unsupported transaction payload type %d", common.HeaderType(payload.Header.ChannelHeader.Type))
return nil, fmt.Errorf("Unsupported transaction payload type %d", common.HeaderType(chdr.Type))
}
}
......@@ -178,10 +178,10 @@ func (b *blocksProviderImpl) seekOldest() error {
return b.client.Send(&common.Envelope{
Payload: utils.MarshalOrPanic(&common.Payload{
Header: &common.Header{
ChannelHeader: &common.ChannelHeader{
ChannelHeader: utils.MarshalOrPanic(&common.ChannelHeader{
ChannelId: b.chainID,
},
SignatureHeader: &common.SignatureHeader{},
}),
SignatureHeader: utils.MarshalOrPanic(&common.SignatureHeader{}),
},
Data: utils.MarshalOrPanic(&orderer.SeekInfo{
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Oldest{Oldest: &orderer.SeekOldest{}}},
......@@ -196,10 +196,10 @@ func (b *blocksProviderImpl) seekLatestFromCommitter(height uint64) error {
return b.client.Send(&common.Envelope{
Payload: utils.MarshalOrPanic(&common.Payload{
Header: &common.Header{
ChannelHeader: &common.ChannelHeader{
ChannelHeader: utils.MarshalOrPanic(&common.ChannelHeader{
ChannelId: b.chainID,
},
SignatureHeader: &common.SignatureHeader{},
}),
SignatureHeader: utils.MarshalOrPanic(&common.SignatureHeader{}),
},
Data: utils.MarshalOrPanic(&orderer.SeekInfo{
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: height}}},
......
......@@ -278,7 +278,17 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro
return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
}
chainID := hdr.ChannelHeader.ChannelId
chdr, err := putils.UnmarshalChannelHeader(hdr.ChannelHeader)
if err != nil {
return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
}
shdr, err := putils.GetSignatureHeader(hdr.SignatureHeader)
if err != nil {
return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
}
chainID := chdr.ChannelId
//chainless MSPs have "" chain name
ischainless := false
......@@ -290,7 +300,7 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro
// Check for uniqueness of prop.TxID with ledger
// Notice that ValidateProposalMessage has already verified
// that TxID is computed propertly
txid := hdr.ChannelHeader.TxId
txid := chdr.TxId
if txid == "" {
err = errors.New("Invalid txID. It must be different from the empty string.")
return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
......@@ -304,7 +314,7 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro
return nil, errors.New(fmt.Sprintf("Failure while looking up the ledger %s", chainID))
}
if _, err := lgr.GetTransactionByID(txid); err == nil {
return nil, fmt.Errorf("Duplicate transaction found [%s]. Creator [%x]. [%s]", txid, hdr.SignatureHeader.Creator, err)
return nil, fmt.Errorf("Duplicate transaction found [%s]. Creator [%x]. [%s]", txid, shdr.Creator, err)
}
}
......
......@@ -106,7 +106,12 @@ func (historyDB *historyDB) Commit(block *common.Block) error {
return err
}
if common.HeaderType(payload.Header.ChannelHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
chdr, err := putils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return err
}
if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
// extract actions from the envelope message
respPayload, err := putils.GetActionFromEnvelope(envBytes)
......
......@@ -122,7 +122,12 @@ func getTxIDandKeyWriteValueFromTran(
return "", nil, err
}
txID := payload.Header.ChannelHeader.TxId
chdr, err := putils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return "", nil, err
}
txID := chdr.TxId
txRWSet := &rwset.TxReadWriteSet{}
......
......@@ -89,7 +89,9 @@ func TestKVLedgerBlockStorage(t *testing.T) {
testutil.AssertNoError(t, err, "Error upon GetEnvelopeFromBlock")
payload2, err := putils.GetPayload(txEnv2)
testutil.AssertNoError(t, err, "Error upon GetPayload")
txID2 := payload2.Header.ChannelHeader.TxId
chdr, err := putils.UnmarshalChannelHeader(payload2.Header.ChannelHeader)
testutil.AssertNoError(t, err, "Error upon GetChannelHeaderFromBytes")
txID2 := chdr.TxId
processedTran2, err := ledger.GetTransactionByID(txID2)
testutil.AssertNoError(t, err, "Error upon GetTransactionByID")
// get the tran envelope from the retrieved ProcessedTransaction
......
......@@ -106,8 +106,13 @@ func (v *Validator) ValidateAndPrepareBatch(block *common.Block, doMVCCValidatio
return nil, err
}
chdr, err := putils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return nil, err
}
valid := false
if common.HeaderType(payload.Header.ChannelHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
txRWSet, err := v.validateEndorserTX(envBytes, doMVCCValidation, updates)
if err != nil {
return nil, err
......@@ -118,13 +123,13 @@ func (v *Validator) ValidateAndPrepareBatch(block *common.Block, doMVCCValidatio
addWriteSetToBatch(txRWSet, committingTxHeight, updates)
valid = true
}
} else if common.HeaderType(payload.Header.ChannelHeader.Type) == common.HeaderType_CONFIG {
} else if common.HeaderType(chdr.Type) == common.HeaderType_CONFIG {
valid, err = v.validateConfigTX(env)
if err != nil {
return nil, err
}
} else {
logger.Errorf("Skipping transaction %d that's not an endorsement or configuration %d", txIndex, payload.Header.ChannelHeader.Type)
logger.Errorf("Skipping transaction %d that's not an endorsement or configuration %d", txIndex, chdr.Type)
valid = false
}
......
......@@ -144,7 +144,13 @@ func getCurrConfigBlockFromLedger(ledger ledger.PeerLedger) (*common.Block, erro
currBlockNumber = block.Header.Number - 1
continue
}
if tx.Header.ChannelHeader.Type == int32(common.HeaderType_CONFIG) {
chdr, err := utils.UnmarshalChannelHeader(tx.Header.ChannelHeader)
if err != nil {
peerLogger.Warning("Failed to get ChannelHeader from Block %d, error %s.", block.Header.Number, err)
currBlockNumber = block.Header.Number - 1
continue
}
if chdr.Type == int32(common.HeaderType_CONFIG) {
return block, nil
}
}
......
......@@ -237,6 +237,10 @@ func getChainID(blockBytes []byte) (string, error) {
if err := proto.Unmarshal(envelope.Payload, payload); err != nil {
return "", err
}
fmt.Printf("Channel id: %v\n", payload.Header.ChannelHeader.ChannelId)
return payload.Header.ChannelHeader.ChannelId, nil
chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return "", err
}
fmt.Printf("Channel id: %v\n", chdr.ChannelId)
return chdr.ChannelId, nil
}
......@@ -228,8 +228,13 @@ func validateProposalResponse(prBytes []byte, proposal *pb.Proposal, visibility
// TODO: validate the epoch
hdr, err := putils.GetHeader(proposal.Header)
if err != nil {
return fmt.Errorf("could not unmarshal the proposal header structure: err %s", err)
}
// recompute proposal hash
pHash, err := putils.GetProposalHash1(proposal.Header, proposal.Payload, visibility)
pHash, err := putils.GetProposalHash1(hdr, proposal.Payload, visibility)
if err != nil {
return fmt.Errorf("could not obtain proposalHash: err %s", err)
}
......
......@@ -85,8 +85,13 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface)
return shim.Error(err.Error())
}
chdr, err := utils.UnmarshalChannelHeader(payl.Header.ChannelHeader)
if err != nil {
return shim.Error(err.Error())
}
// get the policy
mgr := mspmgmt.GetManagerForChain(payl.Header.ChannelHeader.ChannelId)
mgr := mspmgmt.GetManagerForChain(chdr.ChannelId)
pProvider := cauthdsl.NewPolicyProvider(mgr)
policy, err := pProvider.NewPolicy(args[2])
if err != nil {
......@@ -95,9 +100,9 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface)
}
// validate the payload type
if common.HeaderType(payl.Header.ChannelHeader.Type) != common.HeaderType_ENDORSER_TRANSACTION {
logger.Errorf("Only Endorser Transactions are supported, provided type %d", payl.Header.ChannelHeader.Type)
return shim.Error(fmt.Sprintf("Only Endorser Transactions are supported, provided type %d", payl.Header.ChannelHeader.Type))
if common.HeaderType(chdr.Type) != common.HeaderType_ENDORSER_TRANSACTION {
logger.Errorf("Only Endorser Transactions are supported, provided type %d", chdr.Type)
return shim.Error(fmt.Sprintf("Only Endorser Transactions are supported, provided type %d", chdr.Type))
}
// ...and the transaction...
......
......@@ -92,7 +92,7 @@ func createTestBlock(t *testing.T) *common.Block {
Nanos: 0,
},
ChannelId: "test"}
hdr := &common.Header{ChannelHeader: chdr}
hdr := &common.Header{ChannelHeader: utils.MarshalOrPanic(chdr)}
payload := &common.Payload{Header: hdr}
cea := &ehpb.ChaincodeEndorsedAction{}
ccaPayload := &ehpb.ChaincodeActionPayload{Action: cea}
......
......@@ -49,7 +49,12 @@ func SendProducerBlockEvent(block *common.Block) error {
return fmt.Errorf("Could not extract payload from envelope, err %s", err)
}
if common.HeaderType(payload.Header.ChannelHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return err
}
if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
tx, err := utils.GetTransaction(payload.Data)
if err != nil {
return fmt.Errorf("Error unmarshalling transaction payload for block event: %s", err)
......
......@@ -99,7 +99,12 @@ func getChainCodeEvents(tdata []byte) (*pb.ChaincodeEvent, error) {
return nil, fmt.Errorf("Could not extract payload from envelope, err %s", err)
}
if common.HeaderType(payload.Header.ChannelHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return nil, fmt.Errorf("Could not extract channel header from envelope, err %s", err)
}
if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
tx, err := utils.GetTransaction(payload.Data)
if err != nil {
return nil, fmt.Errorf("Error unmarshalling transaction payload for block event: %s", err)
......@@ -154,11 +159,17 @@ func main() {
if txsFltr.IsSet(uint(i)) {
tx, _ := getTxPayload(r)
if tx != nil {
chdr, err := utils.UnmarshalChannelHeader(tx.Header.ChannelHeader)
if err != nil {
fmt.Printf("Error extracting channel header\n")
return
}
fmt.Printf("\n")
fmt.Printf("\n")
fmt.Printf("Received invalid transaction\n")
fmt.Printf("--------------\n")
fmt.Printf("Transaction invalid: TxID: %s\n", tx.Header.ChannelHeader.TxId)
fmt.Printf("Transaction invalid: TxID: %s\n", chdr.TxId)
}
} else {
fmt.Printf("Transaction:\n\t[%v]\n", r)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment