github.com/metacurrency/holochain@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/validate.go (about)

     1  // Copyright (C) 2013-2018, The MetaCurrency Project (Eric Harris-Braun, Arthur Brock, et. al.)
     2  // Use of this source code is governed by GPLv3 found in the LICENSE file
     3  //----------------------------------------------------------------------------------------
     4  
     5  // Chain validation protocol.  This protocol allows DHT nodes to request data so they can
     6  // run validation on the puts and linkings they are asked to perform
     7  
     8  package holochain
     9  
    10  import (
    11  	"bytes"
    12  	"fmt"
    13  	. "github.com/holochain/holochain-proto/hash"
    14  )
    15  
    16  // Package holds app specified data needed for validation (wire package)
    17  type Package struct {
    18  	Chain []byte
    19  }
    20  
    21  // ValidationPackage holds app specified data needed for validation. This version
    22  // holds the package with any chain data un-marshaled after validation for passing
    23  // into the app for app level validation
    24  type ValidationPackage struct {
    25  	Chain *Chain
    26  }
    27  
    28  const (
    29  
    30  	// Constants for the key values of the validation request object returned
    31  	// by validateXPkg functions
    32  
    33  	// PkgReqChain is the key who value is one of the PkgReqChainOptX masks
    34  	PkgReqChain = "chain"
    35  
    36  	// PkgReqEntryTypes is the key who value is an array of entry types to limit
    37  	// the chain to
    38  	PkgReqEntryTypes = "types"
    39  
    40  	// Constant mask values for PkgReqChain key of the validation request object
    41  
    42  	PkgReqChainOptNone       = 0x00
    43  	PkgReqChainOptHeaders    = 0x01
    44  	PkgReqChainOptEntries    = 0x02
    45  	PkgReqChainOptFull       = 0x03
    46  	PkgReqChainOptNoneStr    = "0"
    47  	PkgReqChainOptHeadersStr = "1"
    48  	PkgReqChainOptEntriesStr = "2"
    49  	PkgReqChainOptFullStr    = "3"
    50  )
    51  
    52  // PackagingReq holds a request from an app for data to be included in the validation response
    53  type PackagingReq map[string]interface{}
    54  
    55  // ValidateQuery holds the data from a validation query on the Source protocol
    56  type ValidateQuery struct {
    57  	H Hash
    58  }
    59  
    60  // ValidateResponse holds the response to committing validates (PUT/MOD/DEL)
    61  type ValidateResponse struct {
    62  	Type    string
    63  	Header  Header
    64  	Entry   GobEntry
    65  	Package Package
    66  }
    67  
    68  // MakePackage converts a package request into a package, loading chain data as necessary
    69  // this is the package that gets sent over the wire.  Chain DNA is omitted in this package
    70  // because it can be added at the destination and the chain will still validate.
    71  func MakePackage(h *Holochain, req PackagingReq) (pkg Package, err error) {
    72  	if f, ok := req[PkgReqChain]; ok {
    73  		var b bytes.Buffer
    74  		flags := f.(int64)
    75  		var mflags int64
    76  		if (flags & PkgReqChainOptHeaders) == 0 {
    77  			mflags += ChainMarshalFlagsNoHeaders
    78  		}
    79  		if (flags & PkgReqChainOptEntries) == 0 {
    80  			mflags += ChainMarshalFlagsNoEntries
    81  		}
    82  
    83  		var types []string
    84  		if t, ok := req[PkgReqEntryTypes]; ok {
    85  			types = t.([]string)
    86  		}
    87  
    88  		privateEntries := h.GetPrivateEntryDefs()
    89  		privateTypeNames := make([]string, len(privateEntries))
    90  		for i, def := range privateEntries {
    91  			privateTypeNames[i] = def.Name
    92  		}
    93  
    94  		h.chain.MarshalChain(&b, mflags+ChainMarshalFlagsOmitDNA, types, privateTypeNames)
    95  		pkg.Chain = b.Bytes()
    96  	}
    97  	return
    98  }
    99  
   100  // MakeValidationPackage converts a received Package into a ValidationPackage and validates
   101  // any chain data that was included
   102  func MakeValidationPackage(h *Holochain, pkg *Package) (vpkg *ValidationPackage, err error) {
   103  	vp := ValidationPackage{}
   104  	if (pkg != nil) && (pkg.Chain != nil) {
   105  		buf := bytes.NewBuffer(pkg.Chain)
   106  		var flags int64
   107  		flags, vp.Chain, err = UnmarshalChain(h.hashSpec, buf)
   108  		if err != nil {
   109  			return
   110  		}
   111  		if flags&ChainMarshalFlagsNoEntries == 0 {
   112  			// restore the chain's DNA data
   113  			vp.Chain.Entries[0].(*GobEntry).C = h.chain.Entries[0].(*GobEntry).C
   114  		}
   115  		if flags&ChainMarshalFlagsNoHeaders == 0 {
   116  			err = vp.Chain.Validate(flags&ChainMarshalFlagsNoEntries != 0)
   117  			if err != nil {
   118  				return
   119  			}
   120  		}
   121  	}
   122  	vpkg = &vp
   123  	return
   124  }
   125  
   126  // ValidateReceiver handles messages on the Validate protocol
   127  func ValidateReceiver(h *Holochain, msg *Message) (response interface{}, err error) {
   128  	var a ValidatingAction
   129  	switch msg.Type {
   130  	case VALIDATE_PUT_REQUEST:
   131  		a = &ActionPut{}
   132  	case VALIDATE_MOD_REQUEST:
   133  		a = &ActionMod{}
   134  	case VALIDATE_DEL_REQUEST:
   135  		a = &ActionDel{}
   136  	case VALIDATE_LINK_REQUEST:
   137  		a = &ActionLink{}
   138  	default:
   139  		err = fmt.Errorf("message type %d not in holochain-validate protocol", int(msg.Type))
   140  	}
   141  	if err == nil {
   142  		h.dht.dlog.Logf("got validate %s request: %v", a.Name(), msg)
   143  		switch t := msg.Body.(type) {
   144  		case ValidateQuery:
   145  			response, err = h.GetValidationResponse(a, t.H)
   146  		default:
   147  			err = fmt.Errorf("expected ValidateQuery got %T", t)
   148  		}
   149  	}
   150  	h.dht.dlog.Logf("validate responding with: %T %v (err=%v)", response, response, err)
   151  	return
   152  }