Name the placement ask and a proposal's again and warrant, so the holder asks through the teller as its other asks (ADR 0567 §5, §10, issue 1126)
This commit is contained in:
@@ -361,6 +361,9 @@ type PlacementProposal struct {
|
||||
Ask string `json:"ask,omitempty"`
|
||||
// Words is what happened last, in words (laid again over moved keys, asked again).
|
||||
Words string `json:"words,omitempty"`
|
||||
// Again is when `again` asked the holder to judge it now and raise its ask again (§10); the holder does once per
|
||||
// value.
|
||||
Again time.Time `json:"again,omitempty"`
|
||||
}
|
||||
|
||||
// Nodes is every node whose key the proposal changes, sorted.
|
||||
@@ -447,11 +450,12 @@ func ChangesDigest(p PlacementProposal) string {
|
||||
return "sha256:" + hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// PlacementWarrant is who approved a proposal, through which channel and when (§5, §6), and the ask it answered.
|
||||
// PlacementWarrant is who approved a proposal, through which channel and when (§5, §6): the warrant's id as the teller
|
||||
// wrote it (the ask's id and when), and its words, which name the person and the channel that proved them
|
||||
// (asks.Warrant.Says).
|
||||
type PlacementWarrant struct {
|
||||
Ask string `json:"ask"`
|
||||
Who string `json:"who"`
|
||||
Channel string `json:"channel"`
|
||||
Warrant string `json:"warrant"`
|
||||
Words string `json:"words"`
|
||||
At time.Time `json:"at"`
|
||||
}
|
||||
|
||||
|
||||
@@ -38,14 +38,18 @@ const (
|
||||
// AskKindRecord is the kind of the assigner's ask about a move a person must allow, for a module of policy record:
|
||||
// a composition judged to recreate a container or move data, or one that cannot be judged (ADR 0539 clause 14).
|
||||
AskKindRecord = "record"
|
||||
// AskKindPlacement is the kind of the seat mesh-placement's authorising ask about a proposal (novox/hq ADR 0567 §5):
|
||||
// `placement.<proposal id>`. Its yes is an Approve that only a channel proving who answered takes, never the view.
|
||||
AskKindPlacement = "placement"
|
||||
|
||||
viewWord = "view"
|
||||
)
|
||||
|
||||
// AskKey is an ask's key read whole: its Kind, and the parts its kind has: a merge's Group and heads Hash, a hold's
|
||||
// Module and fingerprint FP, a restore's and a backup's Node, Module and FP, a record's Node, Module and the digest
|
||||
// Composed of the composition it would allow.
|
||||
// Composed of the composition it would allow, a placement's Proposal.
|
||||
type AskKey struct {
|
||||
Proposal string
|
||||
Kind string
|
||||
Group string
|
||||
Hash string
|
||||
@@ -59,13 +63,13 @@ type AskKey struct {
|
||||
// merge's Approve does (ADR 0421 §1, issue 953), the assigner's hold and restore do not. An unknown kind is refused.
|
||||
func AskNeedsProof(kind string) (bool, error) {
|
||||
switch kind {
|
||||
case AskKindMerge:
|
||||
case AskKindMerge, AskKindPlacement:
|
||||
return true, nil
|
||||
case AskKindHold, AskKindRestore, AskKindBackup, AskKindRecord:
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("delivery: %q is not a kind of ask, %s, %s, %s, %s or %s", kind, AskKindMerge, AskKindHold,
|
||||
AskKindRestore, AskKindBackup, AskKindRecord)
|
||||
return false, fmt.Errorf("delivery: %q is not a kind of ask, %s, %s, %s, %s, %s or %s", kind, AskKindMerge, AskKindHold,
|
||||
AskKindRestore, AskKindBackup, AskKindRecord, AskKindPlacement)
|
||||
}
|
||||
|
||||
// HoldAskKey is the key, in AssignerAsksBucket, of the ask about a module's held fingerprint: `hold.<module>.<hex>`.
|
||||
@@ -100,6 +104,15 @@ func BackupAskKey(node, module, fingerprint string) (string, error) {
|
||||
return AskKindBackup + "." + key, nil
|
||||
}
|
||||
|
||||
// PlacementAskKey is the key, in AssignerAsksBucket, of the authorising ask about a proposal of placement:
|
||||
// `placement.<proposal id>` (ADR 0567 §5).
|
||||
func PlacementAskKey(proposal string) (string, error) {
|
||||
if err := CheckProposalID(proposal); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return AskKindPlacement + "." + proposal, nil
|
||||
}
|
||||
|
||||
// RecordAskKey is the key, in AssignerAsksBucket, of the ask about a move of a module on a node to the composition
|
||||
// whose digest it names: `record.<node>.<module>.<digest hex>`, so a new revision at the same fingerprint is asked
|
||||
// again (ADR 0539 clause 14).
|
||||
@@ -154,6 +167,11 @@ func ParseAnyAskKey(key string) (AskKey, error) {
|
||||
return refused(fmt.Errorf("a backup ask is backup.<node>.<module>.<fingerprint hex>"))
|
||||
}
|
||||
return AskKey{Kind: kind, Node: node, Module: module, FP: fp}, nil
|
||||
case AskKindPlacement:
|
||||
if err := CheckProposalID(rest); err != nil {
|
||||
return refused(err)
|
||||
}
|
||||
return AskKey{Kind: kind, Proposal: rest}, nil
|
||||
case AskKindRecord:
|
||||
parts := strings.Split(rest, ".")
|
||||
if len(parts) != 3 {
|
||||
|
||||
@@ -33,9 +33,17 @@ func TestParseAnyAskKey(t *testing.T) {
|
||||
if err != nil || restore != "restore.ace.mesh-mail."+strings.Repeat("d", 64) {
|
||||
t.Fatalf("RestoreAskKey = %q, %v", restore, err)
|
||||
}
|
||||
placement, err := PlacementAskKey("p-one")
|
||||
if err != nil || placement != "placement.p-one" {
|
||||
t.Fatalf("PlacementAskKey = %q, %v", placement, err)
|
||||
}
|
||||
if proof, err := AskNeedsProof(AskKindPlacement); !proof || err != nil {
|
||||
t.Error("a placement ask may be answered without proof of who answered")
|
||||
}
|
||||
for key, want := range map[string]AskKey{
|
||||
hold: {Kind: AskKindHold, Module: "mesh-mail", FP: fp},
|
||||
restore: {Kind: AskKindRestore, Node: "ace", Module: "mesh-mail", FP: fp},
|
||||
hold: {Kind: AskKindHold, Module: "mesh-mail", FP: fp},
|
||||
restore: {Kind: AskKindRestore, Node: "ace", Module: "mesh-mail", FP: fp},
|
||||
placement: {Kind: AskKindPlacement, Proposal: "p-one"},
|
||||
} {
|
||||
if got, err := ParseAnyAskKey(key); err != nil || got != want {
|
||||
t.Errorf("ParseAnyAskKey(%q) = %+v, %v", key, got, err)
|
||||
@@ -44,7 +52,7 @@ func TestParseAnyAskKey(t *testing.T) {
|
||||
if got, err := ParseAnyAskKey(merge); err != nil || got.Kind != AskKindMerge || got.Group != "feat/r4g" || len(got.Hash) != 12 {
|
||||
t.Errorf("ParseAnyAskKey(%q) = %+v, %v", merge, got, err)
|
||||
}
|
||||
for _, bad := range []string{"want.ace.mesh-mail", "hold.mesh-mail", "restore.mesh-mail." + strings.Repeat("d", 64), "approve.x.y", "restore.a.b.c.d", ""} {
|
||||
for _, bad := range []string{"want.ace.mesh-mail", "hold.mesh-mail", "restore.mesh-mail." + strings.Repeat("d", 64), "approve.x.y", "restore.a.b.c.d", "placement.P", ""} {
|
||||
if _, err := ParseAnyAskKey(bad); err == nil || !strings.Contains(err.Error(), "\""+bad+"\"") {
|
||||
t.Errorf("ParseAnyAskKey(%q) = %v, want a refusal naming it", bad, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user