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

     1  // Copyright (C) 2013-2017, 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  package holochain
     6  
     7  import (
     8  	"fmt"
     9  	"github.com/google/uuid"
    10  	. "github.com/holochain/holochain-proto/hash"
    11  )
    12  
    13  type DNA struct {
    14  	Version                   int
    15  	UUID                      uuid.UUID
    16  	Name                      string
    17  	Properties                map[string]string
    18  	PropertiesSchema          string
    19  	PropertiesSchemaFile      string
    20  	AgentIdentitySchema       string // defines what must go in the Indentity field of a key/agent entry
    21  	BasedOn                   Hash   // references hash of another holochain that these schemas and code are derived from
    22  	RequiresVersion           int
    23  	DHTConfig                 DHTConfig
    24  	Progenitor                Progenitor
    25  	Zomes                     []Zome
    26  	propertiesSchemaValidator SchemaValidator
    27  }
    28  
    29  func (dna *DNA) check() (err error) {
    30  	if dna.RequiresVersion > Version {
    31  		err = fmt.Errorf("Chain requires Holochain version %d", dna.RequiresVersion)
    32  	}
    33  	return
    34  }
    35  
    36  // Nucleus encapsulates Application parts: Ribosomes to run code in Zomes, plus application
    37  // validation and direct message passing protocols
    38  type Nucleus struct {
    39  	dna  *DNA
    40  	h    *Holochain
    41  	alog *Logger // the app logger
    42  }
    43  
    44  func (n *Nucleus) DNA() (dna *DNA) {
    45  	return n.dna
    46  }
    47  
    48  // NewNucleus creates a new Nucleus structure
    49  func NewNucleus(h *Holochain, dna *DNA) *Nucleus {
    50  	nucleus := Nucleus{
    51  		dna:  dna,
    52  		h:    h,
    53  		alog: &h.Config.Loggers.App,
    54  	}
    55  	return &nucleus
    56  }
    57  
    58  func (n *Nucleus) RunGenesis() (err error) {
    59  	var ribosome Ribosome
    60  	// run the init functions of each zome
    61  	for _, zome := range n.dna.Zomes {
    62  		ribosome, err = zome.MakeRibosome(n.h)
    63  		if err == nil {
    64  			err = ribosome.ChainGenesis()
    65  			if err != nil {
    66  				err = fmt.Errorf("In '%s' zome: %s", zome.Name, err.Error())
    67  				return
    68  			}
    69  		}
    70  	}
    71  	return
    72  }
    73  
    74  func (n *Nucleus) Start() (err error) {
    75  	h := n.h
    76  	if err = h.node.StartProtocol(h, ValidateProtocol); err != nil {
    77  		return
    78  	}
    79  	if err = h.node.StartProtocol(h, ActionProtocol); err != nil {
    80  		return
    81  	}
    82  	return
    83  }
    84  
    85  type AppMsg struct {
    86  	ZomeType string
    87  	Body     string
    88  }
    89  
    90  // ActionReceiver handles messages on the action protocol
    91  func ActionReceiver(h *Holochain, msg *Message) (response interface{}, err error) {
    92  	return actionReceiver(h, msg, MaxRetries)
    93  }
    94  
    95  func isRelatedHoldMessage(msg *Message) bool {
    96  	return msg.Type == MOD_REQUEST || msg.Type == DEL_REQUEST || msg.Type == LINK_REQUEST
    97  }
    98  
    99  func actionReceiver(h *Holochain, msg *Message, retries int) (response interface{}, err error) {
   100  	dht := h.dht
   101  	// to protect against crashes from background routines after close
   102  	if dht == nil {
   103  		return
   104  	}
   105  	var a Action
   106  	a, err = MakeActionFromMessage(msg)
   107  	if err == nil {
   108  		dht.dlog.Logf("ActionReceiver got %s: %v", a.Name(), msg)
   109  
   110  		// If this is a Del/Mod/Link message then we need to check to see if we
   111  		// have the Related Hash and if not, queue for retry
   112  		if isRelatedHoldMessage(msg) {
   113  			t := msg.Body.(HoldReq)
   114  			err = dht.Exists(t.RelatedHash, StatusDefault)
   115  			if err != nil {
   116  				if err == ErrHashNotFound {
   117  					dht.dlog.Logf("don't yet have %s, trying again later", t.RelatedHash)
   118  					retry := &retry{msg: *msg, retries: retries}
   119  					dht.retryQueue <- retry
   120  					response = DHTChangeUnknownHashQueuedForRetry
   121  					err = nil
   122  				}
   123  			}
   124  
   125  			if response != nil || err != nil {
   126  				return
   127  			}
   128  		}
   129  
   130  		// N.B. a.Receive calls made to an Action whose values are NOT populated.
   131  		// The Receive functions understand this and use the values from the message body
   132  		// TODO, this indicates an architectural error, so fix!
   133  		response, err = a.Receive(dht, msg)
   134  	}
   135  	return
   136  }
   137  
   138  // NewUUID generates a new UUID for the DNA
   139  func (dna *DNA) NewUUID() (err error) {
   140  	dna.UUID, err = uuid.NewUUID()
   141  	if err != nil {
   142  		return
   143  	}
   144  	return
   145  }