Alternative update callback for PointerProperty?
Major edit:

After re-reading batFINGER's answer, I have figured out another way to do this for Bender 2.79+. One of the key points batFINGER highlights is that you can work out which node is the parent by checking all nodes and seeing if the property is a member of one of them. 

Instead of creating a factory though, I created this function that iterates through a node tree and tries to find the node with an attribute that is prop:

def find_prop_node(tree, prop):
    if tree is not None and prop is not None:
        for node in tree.nodes:
            for attr in dir(node):
                if getattr(node, attr) == self:
                    return node
    return None


Now all the property has to do to find its parent node is call find_prop_node from its update function:

class COProperty(PropertyGroup):
    tree = PointerProperty(name="tree", type=NodeTree)
    call = StringProperty(name="call", default="update")

    def callback(self, tree, func):
        self.tree = tree # node.id_name
        self.call = func

    def update(self, context):
        node = find_prop_node(self.tree, self)
        if hasattr(node, self.call):
            getattr(node, self.call)(context)

    origin = FloatProperty(default=1.0, update=update)
    size = FloatProperty(default=1.0, update=update)

    def template_layout(self, layout):
        row = layout.row(align=True)
        row.prop(self, "origin", text="Origin")
        row = layout.row(align=True)
        row.prop(self, "size", text="Size")


The custom Node code now looks like this (note self.id_data instead of self.name):

class CONode(Node, CONodeTree):
    """CO Node"""
    bl_idname = "CONode"
    bl_label = "Origin"
    bl_icon = "OBJECT_DATA"

    def uda(self, context):
        self.update()

    coProp = PointerProperty(type=COProperty, name="coProp")

    def init(self, context):
        self.coProp.callback(self.id_data, "uda")


Because this method isn't reliant on the node's name it isn't susceptible to breaking after a node is renamed. Iterating though the entire node tree might be slower, however.



By adding 2 StringPropertys (parent and call) to the PropertyGroup which store the name of the node that owns it and the function it should call, it can do getattr(self.id_data.nodes[self.parent], self.call)(context):

class COProperty(PropertyGroup):

    parent = StringProperty()
    call = StringProperty(default = "uda")

    def uda(self, context):
        if self.parent in self.id_data.nodes:
            if hasattr(self.id_data.nodes[self.parent], self.call):
                getattr(self.id_data.nodes[self.parent], self.call)(context)

    def callback(self, name, call):
        self.parent = name
        self.call = call

    origin = FloatProperty(default = 1.0, update=uda)
    size = FloatProperty(default = 1.0, update=uda)


To set it up in the node simply call self.coProp.callback(self.name, "uda") in the init (and in update if the name of the node can change):

class CONode(Node, CONodeTree):
    """CO Node"""
    bl_idname = "CONode"
    bl_label = "Origin"
    bl_icon = "OBJECT_DATA"

    def uda(self, context):
        self.update()

    coProp = PointerProperty(type=COProperty, name="coProp")

    def init(self, context):
        self.coProp.callback(self.name, "uda")